Creating custom GSP tags and tag libraries in Grails

ava-s-dmitriy-pavlenko

Grails tag libraries are designed to provide content formatting capabilities right on a GSP page. The ‘tag’ is an action that can be declared in a form of an HTML element. This action can accept an enclosed content and parameters defined as the element attributes to render a modified HTML. For instance, the following built-in tag iterates and renders each element of the list object using the template specified in the content:

The post is written for the Grails version 1.3.7

<!-- tag namespace : tag name -->
<g:each
   in="${[1, 2, 3]}">           <!-- tag attribute (takes the list object) -->
   <p>The number is ${num}</p>  <!-- tag body (provides the template) -->
</g:each>Code language: HTML, XML (xml)

The output:

<p>The number is 1</p>
<p>The number is 2</p>
<p>The number is 3</p>Code language: HTML, XML (xml)

This post is intended for those who do not have aby knowledge of Grails tag libraries, and looking for a way to quickly grasp the general concepts without diving into the documentation.

Creating a custom tag

Custom tag libraries are represented by classes located in the ‘grails-app/taglib’ project directory. Any property of a tag library class, assigned to a closure which takes two arguments, is a recognized as a tag action:

class ExampleTagLib { // tag library class

    def tagAction = { attrs, body // tag library action
        // any tag accepts a list of attributes and an enclosed content:
        // attrs  - a list of attributes
        // body   - a closure, returns the enclosed content
    }
}Code language: JavaScript (javascript)

Let’s create the ‘renderList’ action which takes a list of objects and renders its values using styled ‘span’ elements:

class UtilTagLib {

   def renderList = { attrs, body ->
       // reads the 'values' attribute from the attributes list
       def list = attrs.values
       // iterates and renders list values
       list.each {
          // uses the implicit 'out' variable to append content to the response
          out << "<span class=\"element\"> ${it} </span>"
       }
   }
}Code language: PHP (php)

Now, define the renderList tag on a GSP page using the closure name:

<g:renderList values="[1, 2, 3]" />Code language: HTML, XML (xml)

This results in the following output:

<span class="element"> 1 </span>
<span class="element"> 2 </span>
<span class="element"> 3 </span>Code language: HTML, XML (xml)

Referencing a tag variable

You can pass variables to a content enclosed by a tag and use the enclosed content as a template:

// inside a tag action
out << body((variableName):variableValue) // passes the variable value to the body closureCode language: JavaScript (javascript)
<!-- on a JSP page -->
<namespace:tagname>
    <p>${variableName}</p> <!-- references the variable by name and renders its value -->
</namespace:tagname>Code language: HTML, XML (xml)

For example, here is the ‘iterator’ action which repeats its enclosed content, this action defines the ‘i’ variable that keeps the iteration number:

class UtilTagLib {

   /**
    * @attr times times to iterate
    * @attr iterator the name of the injected 'iterator' variable, default to 'i'
    */
   def iterate = { attrs, body ->
       attrs.times?.toInteger().times { it ->
           // provides the 'i' variable to hold the iteration number
           // or can use the variable name from the 'iterator' attribute
           out << body((attrs.iterator ? attrs.iterator : "i") : it)
       }
   }

   // ...
}Code language: PHP (php)

The GSP page code:

<g:iterate times="3" iterator="j">Iterated ${j} times</g:iterate>Code language: HTML, XML (xml)

or the same code without predefined iterator, when the variable i is used by default:

<g:iterate times="3">Iterated ${i} times</g:iterate>Code language: HTML, XML (xml)

Defining a tag library namespace

Namespaces help to group tag actions and isolate tag libraries in order to avoid naming conflicts. You can define a custom namespace with the static namespace property:

class ExampleTagLib {

    static namespace = "namespaceName"
}Code language: JavaScript (javascript)

For instance:

class UtilTagLib {

    /** The tag library namespace. */
    static namespace = "admin"

    def iterate = { //...
}Code language: JavaScript (javascript)

Now, to use the iterate tag action, you should specify the admin namespace as the tag prefix:

<admin:iterate... >Code language: HTML, XML (xml)

Conclusion

Grails tag libraries are very flexible, and allow to access most of the application scopes or even load data from a database. The only thing to remember here is that they are invoked on a GSP page, and GSP pages are not intended for data loading and processing. Such a heavy lifting should be done by services and controllers, while content formatting must be left to tag libraries which are way more readable than the embedded code blocks.

ava-s-dmitriy-pavlenko
Software Developer & Technical Lead