Tuesday, August 19, 2008

Remembering state of a Grails list page (3)

I'm taking remembering (or maybe I should call it restoring?) the state of a Grails list page a little bit further.

In my Grails project I've added a 'restoreState' method dynamically using the ExpandoMetaClass to all Controller classes. The method is simply added in BootStrap.groovy:

import org.codehaus.groovy.grails.commons.GrailsApplication
import org.codehaus.groovy.grails.commons.metaclass.*

class BootStrap {

def init = { servletContext ->
def application = servletContext.getAttribute(GrailsApplication.APPLICATION_ID)

// add restoreState to controller classes
application.controllerClasses.each { controller ->
controller.metaClass.restoreState << { stateParams ->

// get (or initialize) session state params
def sessionStateParams = delegate.session[delegate.controllerName] = (delegate.session[delegate.controllerName] ?: [:])

// store state params and its values in params and session object
// (1) use params (2) or use session (3) otherwise use default value
stateParams.each { k, v ->
delegate.params[k] = sessionStateParams[k] = (delegate.params[k] ?: (sessionStateParams[k] ?: v))

def destroy = {

The 'restoreState' method can now be invoked from the Controller list action to restore the state of the list page like:

Class AuthorController {

def list = {
restoreState([max: 10, offset: 0, sort: id, order: 'asc'])
[ authorList: Author.list( params ) ]

Note: after writing this entry and using the technique myself I found out that using the BootStrap class to add this restoreState method dynamically is not really useful.

The problem is that it only adds this method during startup of the container and not during reload. So when you change your controller, you loose the method. Solution would be moving this method to a plugin which also depends on the Controller's core plugin, so also during reload the method would be added.

I ended up creating a BaseController which included this method, and my other Controller classes are extending this BaseController. I further installed the Grails templates and changed the Controller templates so they extend the BaseController by default.

Remembering state of a Grails list page (2)

Here is a enhanced version of remembering the state of your Grails list page using a rememberListState method. Just pass in a map of params you want to store in the session and want to use in the list query. The specified param values act as default values.

Controller code:

private rememberListState(stateParams) {
// get (or initialize) session state params
def sessionStateParams = session[controllerName] = (session[controllerName] ?: [:])
// store state params and its values in params and session object
// (1) use params (2) or use session (3) otherwise use default value
stateParams.each { k, v ->
params[k] = sessionStateParams[k] = (params[k] ?: (sessionStateParams[k] ?: v))

def list = {
rememberListState([max: 10, offset: 0, sort: id, order: 'asc'])
[ authorList: Author.list( params ) ]

I think you could even add this rememberListState() method to all Controller classes using the ExpandoMetaClass.

Monday, August 18, 2008

Remembering state of a Grails list page

With the default Grails scaffolding each time you navigate away from the list page (e.g. going to the show page) the state of the list is lost when you return. This can be annoying when you paged to a certain page within the list.

It's easy to make your application remember the state of your list pages. See the example below which is a modified list action:

def list = {
if (!session[controllerName]) session[controllerName] = [:]
if (!session[controllerName]?.max) session[controllerName].max = 10
if (!session[controllerName]?.offset) session[controllerName].offset = 0
if (!session[controllerName]?.sort) session[controllerName].sort = "id"
if (!session[controllerName]?.order) session[controllerName].order = "asc"

params.max = session[controllerName].max = params.max ?: session[controllerName].max
params.offset = session[controllerName].offset = params.offset ?: session[controllerName].offset
params.sort = session[controllerName].sort = params.sort ?: session[controllerName].sort
params.order = session[controllerName].order = params.order ?: session[controllerName].order

[ authorList: Author.list( params ) ]

It stores (per controller) the needed params in the session and when performing the action again, it will take the values from session and your list page remembers its state.

Wednesday, August 13, 2008

Grails on Sakila

After spending some time on Flex and AIR in my spare time - with Peek in Grails as result - I'm happily coding in Grails again. Ahh what a pleasure ;-)

Some time ago I wanted to create a real-life demo application in Grails. Back in May or June I took the MySQL Sakila sample database and started building a Grails application on top of it. I also integrated Yahoo! User Interface Library for a better and richer user experience like using the DataTable (see also the Grails YUI DataTable example).

As I continued working on the demo application I added a YUI MenuBar and customized the Grails scaffolding templates so it generates a YUI enabled user interface.
Currently I'm only using the YUI DataTable, MenuBar, Button and Grids CSS but I want to extend this to use the YUI Calendar, AutoComplete, Rich Text Editor and Charts and perhaps some other nice-looking YUI widgets as well. Under water it also uses required YUI utilities for easily sending XMLHttpRequests and processing JSON results.

I basically only changed the main.gsp, main.css and scaffolding templates and see below what can be generated.

I also created the Grails on Sakila project hosted on Google Code, so if you want you can browse or download the source code yourself. It is currently under development so you are warned.

Friday, August 8, 2008

Word Cloud

After connecting to another Dutch Grails enthousiast (Mr. Haki) on LinkedIn I checked his personal blog and found a nice little tool called Wordle.

Pictures say more then words so look below what you can generate with Wordle.

The above Word Cloud is based on this blog and as expected Grails is on top ;-)

Thursday, August 7, 2008

NLGUG Announced

Just like to mention that I've created a space on Google groups to host the Nederlandse Groovy & Grails User Group (NLGUG). It's a Groovy & Grails User Group for people in The Netherlands.

I started this group to start building up a network of Groovy & Grails developers in The Netherlands. If the group grows and people are interested in meeting up this would be great!

So if you are located in The Netherlands and interested in joining, go to http://groups.google.com/group/nlgug.

Monday, August 4, 2008

Peek in Grails

Last week Marc Palmer announced his Grails Documentation Widget. To bad it was an OS X Dashboard Widget so I couldn't use it on my Windows based machine. Marc already suggested to buy a decent OS... Maybe my boss is reading this someday and buys me an Apple ;-)

When the widget was released I was playing a little bit with Adobe AIR and I decided to port the widget to - or better, create something similar in - Adobe AIR.

It gives you the power to do an incremental search on dynamic methods, tags, scripts etc.

Have a look at http://www.grails.org/Peek+in+Grails for more info and download instructions.