Sunday, March 25, 2012

Ajax Examples upgraded to Grails 2.0.0

Overview
A little over a year ago, I wrote a blog posting providing a complete set of working code showing ajax examples for each of the Grails tags that supports Ajax.   Now, I finally found time to upgrade that code to Grails 2.0.0 (from Grails 1.3.7).   There are plenty of article out there helping point users in the right direction when upgrading to Grails 2.0.0 and most of them are helpful.  Seems like no one wants to RTFM, we just want to get at it!  My recommendation is RTFM, and checkout some of the helpful postings out there, especially when the upgrade includes as many changes and new features as Grails 2.0.0.

I have to confess, I tried to just "get at it" with my ajax application and Grails 2.0.0 and it got me part of the way there.  To finish the job, I needed to read the excellent documentation produced by the Grails team and also the documentation accompanying some of the plugins.

Steps for my upgrade
In order to get my application running under Grails 2.0, I needed 5 basic steps:

  1. Run the 'grails upgrade' against my project.
  2. Upgrade database to use H2 - instructions under Persistence here
  3. Install plugins: prototype and resources plugin.
  4. Modify the main.gsp layout to accommodate the plugins (resource, prototype).
  5. Modify Config.groovy to set the java script library to prototype.
Step 1
This step is required for any application being upgraded from an earlier version of Grails.  I am not going to say anything else about this step.

Step 2
Follow Peter Ledbrook's instructions on upgrading the persistence layer to use H2 database instead of the HSQLDB.  If you want to continue to use HSQLDB, there are instructions for that too!

Step 3
I consider myself 'javascript-challenged', so I decided to stick with the prototype library for javascript for this upgrade rather than attempting to use jQuery, which is the new default library.  If all goes well and I get some free time, maybe I will upgrade the application to use jQuery too, but for now, I am sticking with prototype - less changes too!

Make sure the plugins are installed, and then verify that they all got installed successfully (last statement).

grails install-plugin resources
grails install-plugin prototype
grails list-plugins -installed

Step 4
One of the tricky parts here was including plugin="prototype" on the javascript tag in the header section of this page.  Below is a copy of my layout\main.gsp.  (Be careful using cut/paste on the page below, I had problems with the syntax highligher or blogger (not sure which) adjusting my  html tags as it sees fit).  Best option, grab the code from GitHub. Also be sure to understand the changes needed for the Resources Plugin.
  
 
        <g:layoutTitle default="Grails" />
        
        
        
        
        
           function showSpinner(visible) {
              $('spinner').style.display = visible ? "inline" : "none";
           }
           Ajax.Responders.register({
           onLoading: function() {
                 showSpinner(true);
           },
           onComplete: function() {
             if(!Ajax.activeRequestCount) showSpinner(false);
           }
           });
        
        
    
     
        



        

      
Step 5
Update Config.groovy to define prototype as the javascript library to use.

... 
grails.views.javascript.library = "prototype"
...
The project has been updated  and now available on GitHub.

Hope this helps!

8 comments:

  1. Any chance your going to convert your example to jquery?

    ReplyDelete
    Replies
    1. It is on my todo list, just not at the top. I am looking at MongoDB right now and then maybe have some time to learn jQuery.

      Delete
  2. Thanks for the example - its a tremendous help in addition to the documentation.

    But, for some reason, I'm not getting it. When I run your upgraded application (as well as when I apply the upgrades to the original version), the AJAX behavior is not functional.

    When I click on the ajax/book/list, the table is empty with a message "Book not found with id 1"

    When I click on the "Ajax examples 0.2" link, I get a 404, resource not available error.

    ReplyDelete
    Replies
    1. I am glad it helps but doesn't sound like you are 'there' yet. I would do each of the following to get a better idea of what's going on.

      1)from the grails ajax project root folder enter "grails list-plugins --installed" in order to get Grails to tell you which plugins are actually installed. The important two are a) prototype and b) resources. If these don't appear in the list, then install them.

      The plugins are actually installed in a different place and not under the project folder. For example, on my XP box, they reside at
      C:\Documents and Settings\mike\.grails\\projects\ajax\plugins.


      2) Assuming the plugins are installed, the next thing I generally do is to add some println statements in the controller that I am expecting to hit/execute.

      3) The "Book not found with id 1" issue sounds like the Bootstap.groovy script is not running successfully at startup.

      Hope this helps. Let me know if I can help further.

      Delete
  3. There is an issue with the bootstrap... the author objects seem to be created properly, but a validation exception is raised during the save of the first Book object:


    Error 2012-08-10 14:49:05,088 [pool-4-thread-1] ERROR context.GrailsContextLoader - Error executing bootstraps: Validation Error(s) occurred during save():
    - Field error in object 'ajax.Book' on field 'author': rejected value [null]; codes [ajax.Book.author.nullable.error.ajax.Book.author,ajax.Book.author.nullable.error.author,ajax.Book.author.nullable.error.ajax.Author,ajax.Book.author.nullable.error,book.author.nullable.error.ajax.Book.author,book.author.nullable.error.author,book.author.nullable.error.ajax.Author,book.author.nullable.error,ajax.Book.author.nullable.ajax.Book.author,ajax.Book.author.nullable.author,ajax.Book.author.nullable.ajax.Author,ajax.Book.author.nullable,book.author.nullable.ajax.Book.author,book.author.nullable.author,book.author.nullable.ajax.Author,book.author.nullable,nullable.ajax.Book.author,nullable.author,nullable.ajax.Author,nullable]; arguments [author,class ajax.Book]; default message [Property [{0}] of class [{1}] cannot be null]

    I've used the bootstraps quite a bit and have never seen this error before, so I'm still digging into it.

    ReplyDelete
  4. Did you change the bootstrap file at all? The message seems to indicate that the 'author' of a Book can not be null. At th


    Below is a copy of my current bootstap file for comparison. At one point, someone logged a comment that I was missing the import statements at the top of the script. Also, I just tested setting the gsmith variable to null instead of creating the author and the app comes up but without that book.

    Hopefully it's the imports, but if not - sounds like the Author objects are not getting saved. You can edit the file to start with one property and progressively add more of the properties until you find what prevents the author from being save.


    ************ current version of Bootstrap.groovy ******************
    import ajax.Author
    import ajax.Book


    class BootStrap {

    def init = { servletContext ->

    def gsmith = new Author(firstName:'Glen', lastName:'Smith')
    gsmith.save()
    def pledbrook = new Author(firstName:'Peter' , lastName:'Ledbrook')
    pledbrook.save()
    def rocher = new Author(firstName:'Graeme' , lastName:'Rocher')
    rocher.save()
    def dklein = new Author(firstName:'Dave', lastName:'Klein')
    dklein.save()
    def dierk = new Author(firstName:'Dierk', lastName:'Konig')
    dierk.save()
    def bashar = new Author(firstName:'Bashar', lastName:'Abdul-Jawad')
    bashar.save()
    def fischer = new Author(firstName:'Robert', lastName:'Fischer')
    fischer.save()
    def rudolph = new Author(firstName:'Jason', lastName:'Rudolph')
    rudolph.save()

    new Book(title:'Grails in Action', pages:469 , Author:gsmith , publisher:'Manning' ).save()
    new Book(title:'Groovy in Action', pages:532 , Author:dierk , publisher: 'Manning' ).save()
    new Book(title:'The Definitive Guide to Grails', pages:569 , Author:rocher , publisher:'Apress' ).save()
    new Book(title:'Grails A Quick-Start Guide', pages: 200, Author:dklein , publisher:'Pragmatic Bookshelf' ).save()
    new Book(title:'Groovy and Grails Recipes', pages: 214, Author:bashar , publisher:'Apress').save()
    new Book(title:'Grails Persistence with GORM and GSQL', pages: 214, Author:fischer , publisher:'Apress' ).save()
    new Book(title:'Getting Started with Grails', pages: 131, Author:rudolph , publisher:'InfoQ' ).save()

    }

    def destroy = {
    }
    }

    ReplyDelete
  5. Found it! Not sure how this worked previously but in the Boostrap.groovy Book constructor calls, I have 'Author' as a property instead of 'author'. Change them all to lowercase 'author' and that should correct the problems with books not getting created!

    Thanks for catching that. I will update Github this weekend (I hope!).

    ReplyDelete
  6. Yep - I finally caught that as well and am wondering how I missed it. Thanks again!

    ReplyDelete