Grails
WebFlow enables the ability to keep a context specific to a set of pages. Grails webflow is built on top of Spring webflow but, as always, Grails adds ease of use with a DSL.
When do you need webflow? Whenever you find yourself stuffing things in the session context.
One side note, if you are putting something in the session that is used in the very next request, use the flash context, as it retains items in the flash scope for two request cycles (unless the item is refreshed on the second request.
A webflow is contained in one controller. Reading existing webflows is fairly easy but, until you become comfortable with a few terms, writing webflows can be problematic. Things that you need to understand are Flow Scopes, View States, and Action States.
To get started with webflow, read, in its entirety, the documentation at
WebFlow and then download and play with the
book-flowsample application. If you do not know how to check out a Subversion, email me and I'll walk you through it.
Grails WebFlow seems to be limited somewhat in GSP tags: g:submitButton and g:link. Remember that in the Grails RESTful architecture, URLs follow the domain/controller/action convention to identify the controller and closure (the action) to handle the request. WebFlows adds the concept of an event. Strangely the g:submitButton's name attribute defines the event but the g:link uses the more obvious event attribute. But what if you want to use an image button or invoke a request from a JavaScript event?
If you look at the HTML generated from the g:submitButton or g:link tags you will see a request parameter with a name the is prefixed with _eventId_. The string that follows the second underscore identifies the WebFlow event.
So for an application that requires an image, a click of which should be handled by the
edit event of a webflow:
<input class="edit" name="_eventId_edit"id="_eventId_edit"
value="Edit" type="image"
src="/FAB/images/skin/database_edit.png"
/>
To have a select list that runs the createMop (method of payment) event when a user select a item from the method of payment types list:
<g:select id='mopType' name='mopType'
onchange="location='/FAB/document/documentWork?_eventId_createMop=createMop&'+Form.serialize(\'docLogForm\');"
from='${(BootStrap.mopTypes.entrySet().value)}'
keys='${(BootStrap.mopTypes.entrySet().key)}'
/>
Notice the use of the serialize method of the Form object. The serialize method comes from the prototype JavaScript library.