Section 9.1. Handling Ajax Requests


9.1. Handling Ajax Requests

The first thing to think about when dealing with Ajax is the way the browser and server communicate. From the server side, everything still comes in as an HTTP request and gets passed to the first object to match in the CherryPy controller hierarchy. So, the first thing you generally want to do is set up a controller method that handles an HTTP request and returns the data you eventually want your JavaScript to see.

In general, you will return one of three things to the browser: HTML, XML, or JSON.

9.1.1. Ajax Requests/HTML Responses

An HTML request is definitely the easiest to understand. Your browser makes a request to the server, you return HTML, and the browser hands it back to some JavaScript that will render that HTML at some point in your page. Because it is so simple, and most of the HTML construction work is done on the server, it's often the easiest way to go.

For example, the WhatWhat Status people have methods in the ProjectController that send back an HTML fragment. create_note takes a string as a parameter from the Ajax request that calls it. It then gets the current user ID from the identity object, uses the _active_project_id() function to get the current project ID from a cookie, and saves all of this to the database as a new note. When it's done, it just returns the HTML output that you get when you render a note_widget:

  @tg.expose(fragment=True)   @tg.validate(validators=dict(note=validators.String()))   def create_note(self, note):       creator = Person.get(identity.current.user.id)       project = Project.get(self._active_project_id())       note = Note(creator=creator, project=project, note=note)       return widgets.note_widget.render(note=note, read_only=False)


The resulting HTML is then returned to the browser, which places it in the page using an ultra-simple JavaScript that modifies the DOM (Document Object Model). If you're new to the DOM, don't worry; we talk about it more in the next section. For now, all you need to know is it can write JavaScript that replaces an element of your page with the HTML returned by an Ajax request.

This is often the easiest and cleanest way to do things because it enables you to create HTML from Python using Kid templates, which is something you already have to know how to do. And, although DOM scripting has come a long way since the massive incompatibilities of IE and Netscape 4, it'll probably never be as straightforward as Kid templates.

9.1.2. Ajax Requests/JSON Responses

But sometimes you need to update several different portions of the page, or you want to trigger some kind of visual effect, or you just want to pass a value in to your JavaScript from the server, where you can process it in any way you like.

By far, the easiest way to do this is to use JSON. JSON stands for JavaScript Object Notation, which is just a fancy way of saying that what you pass back is a collection of JavaScript objects in the form of a string. JSON is a subset of JavaScript, so you can eval a JSON response from the server and get an object or set of objects back.

MochiKit provides an easy way to get JSON from the server via loadJSONDoc(), and WhatWhat Status uses this kind of thing, too. For example, you can click Close to close any open risk; that triggers an asynchronous request to delete that risk from the database. Then, when the risk is closed, the server sends back a JSON object with a single Boolean value:

  @tg.expose(allow_json=True)   @tg.validate(validators=dict(risk_id=validators.Int()))   def close_risk(self, risk_id):       risk = Risk.get(risk_id)       risk.closed = True       return dict(success=True)


When the JavaScript in your page receives this value from the browser, it can then update the page to remove that risk. This delayed feedback helps the user know that the element was actually removed from the server (especially when it is coupled with a visual effect, as it will be on this page).

9.1.3. Ajax and XML Responses

You can also return XML to the browser from TurboGears. From the controller side, all you do is define a Kid template, which creates the XML file you'll send back to the browser. In the controller, the only difference between sending a dictionary to a Kid template, which will be rendered into XML for an Ajax request, and sending a dictionary to a Kid template, which will be rendered as an HTML web page, is the content type you choose in the @expose() decorator. The only difference is the content of the Kid template, which will render to some non-XHTML doc type.

This is easy as pie; and if that's all there was to it, you would be just as well off using XML as JSON as your standard communication protocol in your Ajax requests. The problem is what happens at the browser when the XML request is parsed. You have to parse the XML in your JavaScript, which is no problem (unless you want cross-browser support). Several differences between Firefox, Safari, Opera, and Internet Explorer can easily create headaches for you.

For example, Internet Explorer skips whitespace text nodes, whereas Firefox and others maintain the text node, even if it contains only whitespace. Because many XML generators, including Kid, maintain whitespace between elements to nest the emitted code and make it readable, you'll get different results from IE vs. Firefox when you check to see how many child nodes a particular XML element has. But that's probably getting ahead of ourselves a bit; we really haven't talked about the DOM yet. So, if you don't know exactly what the difference between an element and a node is, don't worry about it. Unless you have a specific reason, you'll proably be better off using JSON to send data structures back to your browser.

And for those of you who do have a compelling need to use XML as a transport mechanism, I promise we'll come back to DOM manipulation in JavaScript in a little bit.




Rapid Web Applications with TurboGears(c) Using Python to Create Ajax-Powered Sites
Rapid Web Applications with TurboGears: Using Python to Create Ajax-Powered Sites
ISBN: 0132433885
EAN: 2147483647
Year: 2006
Pages: 202

flylib.com © 2008-2017.
If you may any questions please contact us: flylib@qtcs.net