9.1. Handling Ajax Requests
In general, you will return one of three things to the browser: HTML, XML, or JSON.
9.1.1. Ajax Requests/HTML Responses
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)
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
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)
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.
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.