Simple Ajax with cherrypy and jQuery

All the cool kids these days are putting Ajax into their web applications. Ajax is great for when you want to update data on a page without reloading the entire page. Most of the Ajax tutorials use PHP, so I want to show here how easy it is to do Ajax with cherrpy.

Ajax stands for "asynchronous JavaScript and XML," but these days json is often used as a lighter-weight alternative to XML. In this tutorial, I'm therefore going to show how to use the python simplejson library to enable communication between python and JavaScript using json.

What you will need for this tutorial:

You can get cherrypy and simplejson from pypi via easy_install; there's a copy of jQuery in my sample project. The sample project consists of three files, in the following structure:

ajax_app.py media/ + jquery-1.4.2.min.js | index.html

First, I'll show the HTML file:



<head>

<title>AJAX with jQuery and cherrypy</title>

<script type="text/javascript" src="/media/jquery-1.4.2.min.js"></script>

<script type="text/javascript">

$(function() {

// When the testform is submitted…

$("#testform").submit(function() {

// post the form values via AJAX…

var postdata = {name: $("#name").val()} ;

$.post('/submit', postdata, function(data) {

// and set the title with the result

$("#title").html(data['title']) ;

});

return false ;

});

});

</script>

</head>

<body>

<h1 id="title">What's your name?</h1> AJAX with jQuery and cherrypy $(function() {// When the testform is submitted…$("#testform").submit(function() {// post the form values via AJAX…var postdata = {name: $("#name").val()} ;$.post('/submit', postdata, function(data) {// and set the title with the result$("#title").html(data['title']) ;});return false ;});}); What's your name? <form id="testform" action="#" method="post">

<p>

<label for="name">Name:</label>

<input type="text" id="name" /> <br /> <input type="submit" value="Set" />

</p>

</form>

</body>

</html>

Let's see what this is doing. In the body, you've got a title tag, and bog standard HTML form, which asks for a name.

In the head, you've got an include to the jQuery library, and the following JavaScript code:

$ ( function ( ) {

// When the testform is submitted…

$ ( "#testform" ) . submit ( function ( ) {

// post the form values via AJAX…

var postdata = { name : $ ( "#name" ) . val ( ) } ;

$. post ( '/submit' , postdata, function ( data ) {

// and set the title with the result

$ ( "#title" ) . html ( data [ 'title' ] ) ;

} ) ;

return false ;

} ) ;

} ) ;

The initial $(function() statement is a jQuery construct that says, "When the page loads, execute this anonymous function." That function then creates a callback for the submit event of the element with id "testform" (the form). When the form is submitted, the jQuery post function is executed, which is where the magic happens.

jQuery.post is an Ajax method. The first argument is the URL to post to ("/submit"); the second argument is the data to send in the post (the "name" value from the form); and the third argument is the callback to call with the data we receive from the post.

The function then takes this data, and uses its "title" element to update the title of the page.

Next, here's the ajax_app.py file:

import cherrypy

import webbrowser

import os

import simplejson

import sys cherrypysimplejson MEDIA_DIR = os.path.join(os.path.abspath("."), u"media") class AjaxApp(object):

@cherrypy.expose

def index(self):

return open(os.path.join(MEDIA_DIR, u'index.html')) @cherrypy.expose

def submit(self, name):

cherrypy.response.headers['Content-Type'] = 'application/json'

return simplejson.dumps(dict(title="Hello, %s" % name)) config = {'/media':

{'tools.staticdir.on': True,

'tools.staticdir.dir': MEDIA_DIR,

}

} def open_page():

webbrowser.open("http://127.0.0.1:8080/")

cherrypy.engine.subscribe('start', open_page)

cherrypy.tree.mount(AjaxApp(), '/', config=config)

cherrypy.engine.start()

First, the AjaxApp class is our application. It's pretty simple, having only two methods: index and submit .

When the index method is called, the app opens the index file and returns it.

The submit method is our Ajax method; when it is called with the form data, we use the information to create a new title, and pass that back as json data using simplejson.dumps. The JavaScript function that called this method can then use the data to update the page content.

This little piece of code is a convenience for development; when you run the cherrpy app, it loads the index page in your web browser.

def open_page ( ) :

webbrowser . open ( "http://127.0.0.1:8080/" )

cherrypy. engine . subscribe ( 'start' , open_page )

Finally, the last two lines mount the app, and start up the server. The "config" dict tells cherrpy to serve up static files from the "media" dir in the script's home directory.

If you download the sample project, unzip it, and run ajax_app.py, you should get the following screen (shown here with the name filled in):

Here it is after filling in the name and clicking Set:

When to use Ajax

Ajax is useful when you want to update the page content without reloading the entire page. This is useful for CRUD apps when you want to do things like edit items in place, delete items, or add items.

When not to use Ajax

Since Ajax actions don't correspond to URIs, you can't bookmark Ajax actions, send links to friends, or use the back and forward buttons to navigate like in a normal website.

For this reason, avoid Ajax if you want certain application states to be navigable as URIs. For example, if you have a calendar application, and use Ajax to show all the data, the user won't have any way to bookmark an event on December 12th, 2011. Likewise, if you use an Ajax data grid to show tables of data, you won't be able to email your data views to your colleagues.

One middle way is to offer a "permalink" for each Ajax view, which allows for bookmarking, sending links, etc. This still breaks the back-button functionality, but may be worth the trade-off.