Grails AJAX Examples
Early on, newcomers to Grails encounter a lack of working samples accompanying the framework. Good places for examples and documentation include the Grails documentation and bloggers.
Ajax is one of the features with built-in support by Grails. Once people get their “head around” the Grails basics, they generally want to move onto more interesting features like Ajax. This usually requires scouring the web, looking for examples and/or reading the documentation fairly closely. I went through this process and figured that others might benefit from a set of short working ajax examples in Grails. I have created a small application that demonstrates some of the Ajax features and provide the application for download to anyone interested. (see bottom for download
information)
The example application uses each of the following:
- FormRemote
- RemoteLink
- SubmitToRemote
- RemoteFunction
- RemoteField
General Steps
- Pick your javascript library – prototype used in my example. Also shown is some Ajax event registration.
function showSpinner(visible) { $('spinner').style.display = visible ? "inline" : "none"; } Ajax.Responders.register({ onLoading: function() { showSpinner(true); }, onComplete: function() { if(!Ajax.activeRequestCount) showSpinner(false); } });
- Update your controller with any code needed – below is my entire BookController
package ajax class BookController { def scaffold = true def showEditAjax = { render (view:'editAjax', model:[bookInstance:Book.get(params.id)]) } def showListSelect = { render (view:'listSelect', model:[bookInstanceList:Book.list()]) } def showTitleSearch = { render (view:'titleSearchAjax') } def showRemoteLink = { render (view:'remoteLink', model:[bookInstanceList:Book.list()]) } def showDetails = { render(template:'bookDetails', model:[bookInstance:Book.get(params.id)]) } def showSearch = { render (view:'searchAjax') } def String wrapSearchParm(value) { '%'+value+'%' } def searchTitle = { def list = Book.findAllByTitleIlike(wrapSearchParm(params.searchvalue)) render(template:'searchResults', model:[searchresults:list]) } def search = { def list if (params.publisher && params.title) list = Book.findAllByTitleIlikeAndPublisherIlike(wrapSearchParm(params.title), wrapSearchParm(params.publisher)) else if (params.publisher) list = Book.findAllByPublisherIlike(wrapSearchParm(params.publisher)) else if (params.title) list = Book.findAllByTitleIlike(wrapSearchParm(params.title)) render(template:'searchResults', model:[searchresults:list]) } def listByPublisher = { def list if (params.filter.equals("All")) list = Book.list() else list = Book.findAllByPublisher(params.filter) render(template:'searchResults', model:[searchresults:list]) } def update = { def bookInstance = Book.get( params.id ) if(bookInstance) { bookInstance.properties = params if(!bookInstance.hasErrors() && bookInstance.save()) { render " Book ${params.title} updated with Ajax using FormRemote" } else { render(view:'edit',model:[bookInstance:bookInstance]) } } else { flash.message = "Book not found with id ${params.id}" redirect(action:edit,id:params.id) } } }
- Create/update view(s) – See screen shots below and/or download the application
Most of the examples are fairly straight forward and should not need a lot of explanation. They may not be great ‘real world’ examples but the intention is to provide a working example for someone to start from.
FormRemote
The formRemote taglib creates a form tag that uses a remote uri to execute an ajax call. In this case, I have slightly modified the default generated edit.gsp to change the form tag to a formRemote tag and added a div to show the edit results. The screen shot below shows the result of first clicking the Form Remote navigation menu button, changing the number of pages in the ‘Grails in Action’ book and pressing the Update button at the bottom of the screen.
RemoteLink
The RemoteLink tag creates a link that calls a remote function when clicked. In the example application, I display a list of book titles and the title is a link. Clicking on the title shows the book details at the bottom of the screen.
<g:each in="${bookInstanceList}" status="i" var="bookInstance"> <g:remotelink action="showDetails" id="${bookInstance.id}" oncomplete="showSpinner(false);" onloading="showSpinner(true);" update="bookDetails">${fieldValue(bean: bookInstance, field: "title")}</g:remotelink> </g:each>
SubmitToRemote
The submitToRemote tag creates a button that submits the surrounding form as a remote Ajax call serializing the fields into parameters. In the example application, I created search fields for Title and Publisher. The search button was created using the SubmitToRemote taglib to submit the search parameters using Ajax.
<g:form action="search"><table><tbody> <tr class="prop"> <td class="name" valign="top">Title:</td> <td class="value" valign="top"><input name="title" value="${title}" type="text"></td> </tr> <tr class="prop"> <td class="name" valign="top">Publisher:</td> <td class="value" valign="top"><input name="publisher" value="${publisher}" type="text"></td> </tr> </tbody> </table><g:submittoremote oncomplete="showSpinner(false)" onloading="showSpinner(true)" update="searchresults" url="[controller:'book', action:'search']" value="Search"> </g:submittoremote></g:form>
RemoteFunction
The example application uses the RemoteFunction taglib to create a remote javascript function that is assigned to the onChange DOM event. When the user selects or changes the value in the Publisher dropdown list, the remote function is called and the bottom half of the screen displays books published by the selected Publisher.
RemoteField
The example application uses the RemoteField taglib to create a dynamic search for Book titles, similar to Google Instant. Search results are returned the screen as you type values in the Title Search field. The controller code in this case, wraps the search parameter with the wild card character (%) to search the database and returns all matches to be displayed.
<div id="searchbox">Title Search: <g:remotefield name="search" oncomplete="showSpinner(false);" onloading="showSpinner(true);" paramname="searchvalue" update="searchresults" url="[controller:'book', action:'searchTitle']"> </g:remotefield></div>
Problems Encountered
- I ran into problems trying to get the spinner to show correctly until I found this entry on StackOverflow that showed how to register the Ajax events. When running locally on the same box, this happens very fast so you really need to keep and eye on the upper right corner of the screen if you want to see the spinner.
- I also ran into problems with the RemoteFunction due to syntax problems. Being used to the taglibs, I was setting the update parameter using update=”mydiv” when the syntax should have been update:”mydiv”. This did not flag as an error. The controller was called, it just never updated the target div!
Downloads
- Download a zip from here
- Get a copy from Github – this is my first crack at creating a repo at Github, so if I did it wrong, please let me know.
It was fun putting this together. Hope it helps some of you!
Good Job!
Hi,
This ajax calls are using grails tags.
it there a way to make ajax calls using Jquery ? I am having hard time finding document that
guide me for that.
I have tried to build ajax response using “render object as JSON” but it does not work.
if you can point me to something that will be really helpful.
Thanks,
Bhavin