Groovy

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

It was fun putting this together.   Hope it helps some of you!
 

Reference: Grails AJAX Examples from our JCG partner Mike Miller at the Scratching my programming itch blog.

Mike Miller

Mike is a software developer who loves to learn how things work. A Java programmer who caught the Groovy & Grails itch and is always looking for opportunities to include them as part of the solution.
Subscribe
Notify of
guest

This site uses Akismet to reduce spam. Learn how your comment data is processed.

2 Comments
Oldest
Newest Most Voted
Inline Feedbacks
View all comments
Anonymouse
Anonymouse
10 years ago

Good Job!

bravo
bravo
10 years ago

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

Back to top button