07 October 2008

Make Freemarker work with Prototype's Ajax.Request

The popular Ajax.Updater from Prototype is great for getting little bits of HTML back from your server and sticking them in your client's page somewhere. But Prototype has some other tricks hidden up its sleeve. The Ajax.Request utility (upon which Ajax.Updater is based) has a very nice feature: if the response comes with content-type "application/javascript" (or equivalent), it evaluates the response body as if it were javascript code. Imagine that: the server can send any arbitrary piece of code back to the client to be executed on the client's machine.

Any kind of ajax-based state change could use this technique: a login, a deletion, an insertion. For example, after a deletion, you might wish to return this response:

widget-deleted.ftl
${res.setContentType("application/javascript")};
alert('widget ${widgetId} successfully deleted');
$('div_for_widget_${widgetId}').remove();

- to provide feedback to the user in two ways: an alert, followed by the disappearing of the dom element representing the deleted object.

You might even find this technique useful to resolve the ages-old dilemma of whether to perform input validation on the server or on the client. Up to now, the correct answer has been (frustratingly) "both". But now you can avoid duplicating validation code in javascript: instead you have a javascript response that provides server-side validation-failed feedback to your user.

Here's another example, for an application that takes comments, and requires a non-empty comment. The first indicates a successful comment submission:

comment-ok.ftl
${res.setContentType("application/javascript")}
alert("Your comments have been noted. Thank you.");
$('commentForm').hide();

And the second, failure:

comment-failed.ftl
${res.setContentType("application/javascript")}
alert("You didn't enter a comment!");

Your controller decides which response template to evaluate after having performed the relevant validation. Webwork/Struts2 makes this decision based on its "struts.xml" configuration and the outcome of your action.

The first line in each of these examples sets the content type of the response so that Prototype knows to interpret it as code. The MVC framework you are using should have inserted some variable in the Freemarker context to represent the response - in the case of Webwork/Struts2, it's called "res".

Don't go overboard with Ajax though - keep in mind Ajax breaks bookmarkability and browsers' back/forward buttons. Distinguish between requests that access and display resources - a bookmarkable url is nice here, and actions that modify state on the server - Ajax.Request might be useful here, unless the state change should take you to a new page.

Let me know how this works for you!

No comments:

Post a Comment