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.