Ajax Support
Introduction
Ajax stands for Asynchronous Javascript and XML and is the driving force behind the shift to richer web applications. These types of applications in general are better suited to agile, dynamic frameworks written in languages like Ruby and Groovy. Grails provides support for building Ajax applications through its Ajax tag library. For a full list of these see the Tag Library Reference.Rails developers will be familiar with the tag library as there are equivalent helper methods in Rails for most of Grails' Ajax tags.Adaptive Ajax Tags
One major difference with Grails' tags is that they are not tied to the Prototype library. For the Grails Ajax tags to work you need to include a supported Ajax library within the "head" tag of your HTML document. The tags will then "adapt" to the included library.Ajax with Prototype:<g:javascript library="prototype" />Ajax with Yahoo UI:
<g:javascript library="yui" />Ajax with Dojo:
<g:javascript library="dojo" />The tags can then be used as described in the following documentation without knowing the details of the underlying implementation. This allows you to choose which library is best suited for your needs as each provides its own benefits.
Installing Dojo
If you choose to use dojo because it is quite a large framework it does not come bundled with Grails and requires installing. Luckily, Grails provides a target to do this for you. Type the following from the root of a Grails project and dojo will be downloaded and setup automatically:grails install-plugin dojo
Installing YUI
If you choose to use YUI, because it is quite a large framework, it does not come bundled with Grails and requires installing. Luckily, Grails provides a target to do this for you. Type the following from the root of a Grails project and YUI will be downloaded and setup automatically:grails install-plugin yui
Loading Remote Content
Remote content can be loaded in a number of ways, the most commons way is through the "remoteLink" tag. This tag allows the creation of HTML anchor tags that perform an asynchronous request and optionally set the response in an element. The simplest way to create a remote link is as follows:<g:remoteLink action="delete" id="1">Delete Book</g:remoteLink>
The above link sends an asynchronous request to the "delete" action of the current controller with an id of "1". This is great, but usually you would want to provide some kind of feedback to the user as to what has happened:
def delete = {
def b = Book.get( params.id )
b.delete()
render "Book ${b.id} was deleted"
}<div id="message"></div> <g:remoteLink action="delete" id="1" update="message">Delete Book</g:remoteLink>
The above example will call the action and set the contents of the "message" div to the response in this case "Book 1 was deleted". This is done by the "update" attribute on the tag, which can also take a map to indicate what should be updated on failure:
<div id="message"></div> <div id="error"></div> <g:remoteLink action="delete" id="1" update="[success:'message',failure:'error']">Delete Book</g:remoteLink>
Here the error div will be updated if the request failed.
Handling Events
Specific javascript can be called if certain events occur, all the events start with the "on" prefix and allow you to give feedback to the user where appropriate, or take other action:<g:remoteLink action="show" id="1" update="success" onLoading="showProgress();">Show Book 1</g:remoteLink>
The above code will execute the "showProgress()" function which may show a progress bar or whatever is appropriate. Other events include:
- onSuccess (optional) - The javascript function to call if successful
- onFailure (optional) - The javascript function to call if the call failed
- on_ERROR_CODE (optional) - The javascript function to call to handle specified error codes (eg on404="alert('not found!')")
- onUninitialized (optional) - The javascript function to call the a ajax engine failed to initialise
- onLoading (optional) - The javascript function to call when the remote function is loading the response
- onLoaded (optional) - The javascript function to call when the remote function is completed loading the response
- onComplete (optional) - The javascript function to call when the remote function is complete, including any updates
Submitting a Form remotely
An HTML form can also be submitted asynchronously in one of two ways. Firstly using the "formRemote" tag which expects similar attributes to those for the "remoteLink" tag:<g:formRemote url="[controller:'book',action:'delete']" update="[success:'message',failure:'error']"> <input type="hidden" name="id" value="1" /> <input type="submit" value="Delete Book!" /> </g:formRemote >
<form action="delete"> <input type="hidden" name="id" value="1" /> <g:submitToRemote action="delete" update="[success:'message',failure:'error']" /> </form>
Multiple buttons with formRemote
There is a problem with Prototype (up to and including 1.5.1 at the time of writing) that means Grails can not determine which button has been pressed when aformRemote tag includes more than one submit button. One simple workaround is to use a standard form with submitToRemote tags for the buttons. Here's an example:
<g:form name="editUserRolesForm" url="[ id: project.id ]"> <!-- The table of roles that each user has in this project. --> <table class="roleTable"> <!-- Put the role names in the header. --> <tr> <th/> <g:each in="${roles}" var="role"> <th><g:link controller="role" action="show" id="${role.id}">${role.name}</g:link></th> </g:each> </tr> <!-- Now output each user on a separate row. --> <g:each in="${users}" var="username"> <tr> <td>${username}</td> <g:each in="${roles}" var="role"> <td><g:checkBox name="role_${username + '_' + role.id}" value="${userProjectRoles.contains('role_' + username + '_' + role.id)}" /></td> </g:each> </tr> </g:each> </table> <span> <g:submitToRemote update="userRoleTable" action="saveUserRoles" id="${project.id}" value="Update" /> <g:submitToRemote update="userRoleTable" action="cancelEditUserRoles" id="${project.id}" value="Cancel" /> </span> </g:form>
Ajax and the Render Method
Grails' render method is the perfect companion for creating Ajax responses in a number of ways. As an example lets take a look at an example that retrieves the current date and time:…
// controller action
def time = {
render "${new Date()}"
}
…
<g:remoteLink action="time" update="time">Get Time</g:remoteLink>
<div id="time">Time to be displayed here</div>Here the render method is used to update the "time" div with the current time. However, the render method can also be used to render markup:
…
// controller action
def time = {
render(contentType:'text/xml') {
time(new Date())
}
}
…
// resulting response
<time>(the current time)</time>But it gets even better, you can also render JSON responses using the same builder syntax:
…
// controller action
def time = {
render(builder:'json') {
time(new Date())
}
}
…
// resulting JSON response
{ time: "..." }And if you want to leverage the OpenRico framework you can create OpenRico responses:
…
// controller action
def time = {
render(builder:'rico') {
element(id:'time') {
new Date()
}
}
}
…
// resulting Rico response
<ajax-response>
<response type="element" id="time">
… // current time here
</response>
</ajax-response>


