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.
Here’s the checklist you need to follow to utilise the component.
- install it with grails install-plugin grails-ui
- Modify <body> tag in views/layouts/main.gsp to include class=”yui-skin-sam” attribute.
- Add gui:Dialog tag to your GSP page (views/tekEvent/show.gsp in my case).
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.
So if you go back to the gui:dialog, you will see it:
- get triggered (activated) by the click event of the volunteerButton
- 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.
and here’s how it’s utilised in GSP page:
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.
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.
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!
The <g:remoteLink> calls into the volunteers action of my TekEventController:
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
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.
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!
And this is where I found the gui:dialog tag was rather inflexible.
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.
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.
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.
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.
Tidying up, I:
- removed the bogus onchange listener for the volunteerButton custom tag
- removed the g:remoteLink