Updating multiple parts of a web page in Grails with YUI flavoured piggybacked Ajax calls.

I’ve been running against the Grails 1.2 snapshot, built off the source from Git on my new Macbook Pro.

After using Spring Tool Suite for a while, I made the switch to IntelliJ 9 and haven’t looked back. Great GSP support and easy navigation to plug-ins are amongst the key benefits I’ve noticed.
But I have been caught out on occasion by updates not taking when you’re trying things out in the browser, developing on the fly. You think you’re running against the latest changes, but you’re not…

I recently finished typing in the code for Dave Klein’s Grails: A Quick-Start Guide.

In the book Dave utilised the Grails UI plug-in based on the YUI Dialog component for part of the application.
Here’s a snapshot of the Dialog the application creates.

initiated by clicking "Volunteer for this event"

Here’s the checklist you need to follow to utilise the component.

  1. install it with grails install-plugin grails-ui
  2. Modify <body> tag in views/layouts/main.gsp to include class=”yui-skin-sam” attribute.
  3. Add gui:Dialog tag to your GSP page (views/tekEvent/show.gsp in my case).

gui:Dialog tag code

By utilising the form atttibute in the gui:dialog tag, a form tag gets generated using the controller and action attributes as follows:

<form id="volDialogForm" action="/TekDays/tekEvent/volunteer" method="POST">

with the embedded:

<input type="hidden" name="id" value="11">

The 11 is generated on the fly at run time by embedding the id property of the tekEvent instance.
This will then be accessible in the controller.

TekEventController "volunteer" action

So if you go back to the gui:dialog, you will see it:

  1. get triggered (activated) by the click event of the volunteerButton
  2. replaces a div called “volunteerSpan” which effectively swaps out the button for the rendered response from the controller.

Here’s the piece of GSP code – implemented as a custom tag, with the volunteerButton itself inside the volunteerSpan.

volunteerButton custom GSP

and here’s how it’s utilised in GSP page:

Volunteer Tag in show.gsp

Now we come to the part where I customised this code.

I wanted that Volunteer for this Event button click to also update the section on the screen where the volunteers were listed at the same time (just the one person William Mannion in application above).

So I refactored the TekEvent/show.gsp to introduce a template for the part of the page I wanted to re-render and wrapped this in a div tag around it.

Here I came across the first dragon to slay! Don’t put div tags around tr tags! When Grails generates the HTML to render it won’t appear! I’m guessing there’s a rule about HTML I was caught out by here.

div "volunteers" for list of updated volunteers

div "volunteers" for list of updated volunteers

views/tekEvent/_volunteers.gsp

To begin with I used the <g:remoteLink tag> to test the refresh functionality was in order by clicking on a link that said Refresh after I’d clicked Volunteer for Event.

g:remoteLink

g:remoteLink to update "volunteers" div

Another gotcha here... Be sure to include Prototype Ajax library. Otherwise the rendering of the template occurs in a new page all on its own!

Add Prototype library to tekEvent/show.gsp

The <g:remoteLink> calls into the volunteers action of my TekEventController:

volunteers action

With that working, I now had working code that I should be able to piggyback a second Ajax request with.
I’d been made aware of the <g:remotefunction> tagby Dave Klein, that can

create a remote javascript function that can be assigned to a DOM event to call the remote method

and thought I’d give that a try.

My initial thoughts were to kick off a second Ajax request by detecting an “onchange’ event for the VolunteerSpan where the button get replaced by the “Thanks for volunteering” message.

Volunteer button changes to "Thanks for Volunteering"

Miserable onchange event for span

This didn’t seem to work, so I placed a JavaScript alert into the onchange event.

When that didn’t appear, I did a bit of digging to find I couldn’t get that to work because onchange events only seem to be allowed for form fields!

Span onchange with alert

And this is where I found the gui:dialog tag was rather inflexible.

You see g:remotefunction and g:remotelink allow you to call a JavaScript function before or after the function itself gets invoked.

This is akin to the Template pattern, interceptors, AOP and the like…

If the Grails UI tag added before and after attributes, you could specify var names of functions in script tags that it would hook into.

Matthew Taylor and Daniel Honig were able to provide these links which helped me a bit with my quest 1 2

Luckily I also had a copy of Dan Wellman’s Packt book, Learning YUI to hand too to iron out the kinks in Daniels post on Matthew’s blog.

Learning YUI

In the end I got rid of the gui:dialog node all together, and copied some of the generated code and adapted it for my purposes to tweak the onSuccess functionality.

Here’s the JavaScript code:

Hacked YUI JavaScript code with piggybacked Ajax call

Hacked YUI JavaScript code with piggybacked Ajax call

Heres’ the div scaffolding to render dialog, placed in body tag of my tekEvent/show.gsp page.

This latter part is more or less a cut and paste from view source gui:Dialog tag initially generated.

Of course I had to put the tekEventInstance substitution parameters back into the HTML for the title and the id in the hidden form field.

Div tag scaffolding for Dialog

Tidying up, I:

  1. removed the bogus onchange listener for the volunteerButton custom tag
  2. removed the g:remoteLink
  3. the Prototype JavaScript reference tags
Advertisements

About this entry