Have you used PJAX yet (PushState + AJAX = PJAX)? It’s a pretty slick way to make AJAX partial updates a lot better compared to the regular g:remoteLink tag. The primary benefits are you don’t break the back button functionality and it updates the URL!

The key to implementing PJAX is that you need to have a “chrome-less” view for PJAX requests. This means the view can’t have the main.gsp layout applied to it (or whatever your layout is called). There are a number of different ways you could do this. First, you could simply look for the HTTP header that PJAX adds to each request called X-Pjax and then apply a different layout in the controller (or no layout at all). The approach I decided to take was a little different though. I decided that I didn’t want to modify any controllers and instead do it at the framework level. I also didn’t want to modify any views that already have the meta.layout (<meta name=”layout” content=”main”/>). My solution was to extend GrailsLayoutDecoratorMapper with my own new class called PjaxDecoratorMapper. I was originally going to create a Grails PJAX plugin to take care of this, but you need to modify sitemesh.xml in order to register this new decorator and I don’t believe there currently is any programmatic way to do that (like you can with web.xml). Also, the way that I’m implementing PJAX is certainly not the only way in a Grails app so I’m not sure how much value a plugin would even really provide. If people like this approach and it provides value, I’m certainly open to creating a plugin though. Let me know! So, let’s dive in!

First, we need to get the PJAX JavaScript:

  • grails create-app pjaxsample
  • cd pjaxsample/web-app/js
  • curl -O https://raw.github.com/defunkt/jquery-pjax/master/jquery.pjax.js

Edit grails-app/conf/ApplicationResources.groovy to look like the following:

Next, we need to create a layout that will only be used for our PJAX requests.

Create a new grails-app/views/layouts/pjax.gsp that looks like this:

As you can see, all this layout is doing is rendering the body wrapped in a div called main. You can obviously call this div whatever you want or have multiple layouts for different divs that you want to use PJAX with if needed. For my needs, I simply wanted to always update one common area with PJAX, so just using one div for this met my needs.

Now let’s create our new decorator and configure it with sitemesh!

Create a new src/groovy/grails/pjax/PjaxDecoratorMapper.groovy file that looks like this:
Then modify the decorator-mappers part of web-app/WEB-INF/sitemesh.xml so it looks like this:

As you can see in the Groovy code, all it’s doing is adding a new check for the X-Pjax header and using the pjax.gsp layout if it finds it. Then in sitemesh.xml, we are setting our new class to be the decorator instead of the default one. This is the key to not having to modify any existing controllers or views since this check is happening at the framework level as opposed to in app code. With this stuff in place, now we are ready to use some PJAX! I decided to take the first approach outlined on the PJAX README by using a data attribute on any links I’d like PJAX-ified and then including this JavaScript in web-app/js/application.js. You certainly don’t have to use this approach though and can play with the other ones if you’d like!

In the screencast below, I will now demonstrate using this PJAX setup in a sample application! You can download all the source for this screencast on GitHub: https://github.com/gr8casts/pjaxsample.

I hope you enjoyed this post about using PJAX in Grails! Please let me know in the comments if you have any suggestions for ways to improve PJAX usage in Grails and if you found this valuable or not. Thanks for reading & watching!

9 comments so far

Add Your Comment
  1. That’s pretty slick! Thanks for sharing!

  2. Great article. I did not even know about PJAX until this post, thank you very much.

  3. […] Add Some PJAX to Grails […]

  4. Great article, very excited to use it in my app. Worth knowing is that the jquery plugin has a default timeout of 1000ms which was not long enough for me in my development environment with real content. When the timeout is exceeded it reissues the request without the pjax header. The github page documents how to set a longer timeout.

  5. @Gavin Thanks for the callout about the timeout!

  6. Looks good. Couple of questions:

    1) What happens when you refresh the page after clicking the Foo or Bar PJAX links? I notice the URL changes, so I take it the standard ‘foo’ or ‘bar’ views are rendered including the layout?

    2) Does this only work for links, or form submissions and buttons as well?

  7. @Peter 1) Yes, the standard views will be rendered including the main layout. 2) Should work for buttons with no problem, but I don’t think it will work with form submissions. I’d have to try it out to verify.

  8. @Peter ,@bobby .yes it support form submission now.
    code as below:
    $(document).on(‘submit’, ‘form[data-pjax]’, function(event) {
    $.pjax.submit(event, ‘#pjax-container’);