Grails Pagination Done Right

In it's simplest form, pagination in Grails is quite straight forward, but what happens when you deviate from the simple?  Dynamic finders to the rescue!

Problem:  Provide pagination for a subset of domain objects

Answer:  See the code below

Domain Object

class Cycle {
     String manufacturer
}
Listing 1 - Cycle.groovy

 

Controller

We need to be able to select cycles based upon their manufacturer (ie. Honda, Yamaha, Kawasaki, etc.).  The manufacturer we wish to query on will be included in the request as a parameter.

class CycleController {
    def index = {
        params.max = Math.min( params.max ? params.max.toInteger() : 16,  100)
        
            def cycleCount = Cycle.countByManufacturer(params.manufacturer)
            def cycles = Cycle.findAllByManufacturer(params.manufacturer, [max: params.max as Integer, offset: params.offset as Integer])

        [ cycleInstanceList: cycles, cycleInstanceTotal: cycleCount ]
    }
}
Listing 2 - CycleController.groovy
 

It's important to note the need to cast the values of parameters max and min to Integer.  If this is not done, max and min will not work for pagination.  I thought autoboxing would work in this case, but it doesn't.

The countBy* dynamic query is a great way to get counts without being resource intensive.  A countBy needs to be performed because calling size() on the cycles list will only give the size of the list (in this case 16) as limited by the max parameter.

index.gsp - Paginate Tag


Listing 3 - index.gsp
 

The params tag is included so that when pagination buttons are clicked, the required manufactured parameter will be passed to the controller and used to limit the results to the desired manufacturer.

I hope this helps many of you with pagination.  Of course, things can always get more complicated, that's when critera queries are needed, but in most cases, dynamic finders will suffice.

Comments:

simplify finder

by mike on October 15, 2009 at 6:38 AM CDT
I think you can even further simplify your dynamic finder by passing the params as the second parameter directly: def cycles = Cycle.findAllByManufacturer(params.manufacturer, params)

pagination

by Tiago on February 2, 2010 at 5:15 AM CST
You save my day, thanks

Well done

by Greg on February 18, 2010 at 8:05 PM CST
Nice example on pagination. I have just started playing with grails and found the example in the Grails docs a bit too simple. This is what I was looking for and it works great.

Thanks!!!

by Al on July 25, 2010 at 12:27 PM CDT
Thanks so much Dean! This example is just what I needed to get my pagination working.
Subject*
Name*
Comment*