# paginate

## Purpose

Creates next/previous buttons and a breadcrumb trail to allow pagination of results

## Examples

Example domain class:

    class Book {
         String title
         String author
    }

Example controller:

    class BookController {
      def list = {
         [books: Book.list(params)]
      }
    }

Paginate code:

    <g:paginate controller="book" action="list" total="${Book.count()}" />

or

    <g:paginate next="Forward" prev="Back"
                maxsteps="0" controller="book"
                action="list" total="${Book.count()}" />

## Description

Attributes

- `total` (required) - The total number of results to paginate
- `action` (optional) - the name of the action to use in the link, if not specified the default action will be linked
- `controller` (optional) - the name of the controller to use in the link, if not specified the current controller will be linked
- `id` (optional) - The id to use in the link
- `params` (optional) - A map containing request parameters
- `prev` (optional) - The text to display for the previous link (defaults to "Previous" as defined by default.paginate.prev property in I18n messages.properties)
- `next` (optional) - The text to display for the next link (defaults to "Next" as defined by default.paginate.next property in I18n messages.properties)
- `max` (optional) - The number of records displayed per page (defaults to 10). Used ONLY if params.max is empty
- `maxsteps` (optional) - The number of steps displayed for pagination (defaults to 10). Used ONLY if params.maxsteps is empty
- `offset` (optional) - Used ONLY if params.offset is empty

## Source

Show Source

    def paginate = { attrs ->
            def writer = out
            if (attrs.total == null) {
                throwTagError("Tag [paginate] is missing required attribute [total]")
            }        def messageSource = grailsAttributes.messageSource
            def locale = RCU.getLocale(request)        def total = attrs.int('total') ?: 0
            def action = (attrs.action ? attrs.action : (params.action ? params.action : "list"))
            def offset = params.int('offset') ?: 0
            def max = params.int('max')
            def maxsteps = (attrs.int('maxsteps') ?: 10)        if (!offset) offset = (attrs.int('offset') ?: 0)
            if (!max) max = (attrs.int('max') ?: 10)        def linkParams = [:]
            if (attrs.params) linkParams.putAll(attrs.params)
            linkParams.offset = offset - max
            linkParams.max = max
            if (params.sort) linkParams.sort = params.sort
            if (params.order) linkParams.order = params.order        def linkTagAttrs = [action:action]
            if (attrs.controller) {
                linkTagAttrs.controller = attrs.controller
            }
            if (attrs.id!=null) {
                linkTagAttrs.id = attrs.id
            }
            linkTagAttrs.params = linkParams        // determine paging variables
            def steps = maxsteps > 0
            int currentstep = (offset / max) + 1
            int firststep = 1
            int laststep = Math.round(Math.ceil(total / max))        // display previous link when not on firststep
            if (currentstep > firststep) {
                linkTagAttrs.class = 'prevLink'
                linkParams.offset = offset - max
                writer << link(linkTagAttrs.clone()) {
                    (attrs.prev ? attrs.prev : messageSource.getMessage('paginate.prev', null, messageSource.getMessage('default.paginate.prev', null, 'Previous', locale), locale))
                }
            }        // display steps when steps are enabled and laststep is not firststep
            if (steps && laststep > firststep) {
                linkTagAttrs.class = 'step'            // determine begin and endstep paging variables
                int beginstep = currentstep - Math.round(maxsteps / 2) + (maxsteps % 2)
                int endstep = currentstep + Math.round(maxsteps / 2) - 1            if (beginstep < firststep) {
                    beginstep = firststep
                    endstep = maxsteps
                }
                if (endstep > laststep) {
                    beginstep = laststep - maxsteps + 1
                    if (beginstep < firststep) {
                        beginstep = firststep
                    }
                    endstep = laststep
                }            // display firststep link when beginstep is not firststep
                if (beginstep > firststep) {
                    linkParams.offset = 0
                    writer << link(linkTagAttrs.clone()) {firststep.toString()}
                    writer << '<span class="step">..</span>'
                }            // display paginate steps
                (beginstep..endstep).each { i ->
                    if (currentstep == i) {
                        writer << "<span class=\"currentStep\">${i}</span>"
                    }
                    else {
                        linkParams.offset = (i - 1) * max
                        writer << link(linkTagAttrs.clone()) {i.toString()}
                    }
                }            // display laststep link when endstep is not laststep
                if (endstep < laststep) {
                    writer << '<span class="step">..</span>'
                    linkParams.offset = (laststep -1) * max
                    writer << link(linkTagAttrs.clone()) { laststep.toString() }
                }
            }        // display next link when not on laststep
            if (currentstep < laststep) {
                linkTagAttrs.class = 'nextLink'
                linkParams.offset = offset + max
                writer << link(linkTagAttrs.clone()) {
                    (attrs.next ? attrs.next : messageSource.getMessage('paginate.next', null, messageSource.getMessage('default.paginate.next', null, 'Next', locale), locale))
                }
            }
        }