Sunday, September 27, 2009

Getting data into Grails tags and templates

In the post describing how to create and use grails templates and tags I made short example that showed how gsp pages can be readable if you are using tags and templates. One of the questions asked in comments was how do I get data into tag and/or template. Instead writing answer as comment I decided to write the whole post.

Scoped variables
Common way to get data into tag and template is using Grails scoped variables like application, session, request. This means that both, tags and templates, have access to those variables so you can use them.

Templates
To send data into templates you can and should use standard approach with the grails model.

For example if you are rendering template from tag or from controller (or some groovy code) you should use construct like this one:

render(template:"/templates/common/messageBoxTemplate", model:[title:"hello world"])

If you are rendering template from gsp page you should use construct like this one (actually taken from grails documentation):

<g:render template="displaybook" model="['book':book,'author':author]" />

To be honest I try to avoid using <g:render... from gsp pages because if you are using tags it is easier to read the gsp page. Another advantage of using tags is that it is easier to refactor the gsp pages. So when you find yourself writing <g:render template.... in the gsp page, introduce grails tag for that.

Tags

The advantage of tags is that they have access to the GORM classes and you can inject any grails service into tag. So if you need to perform some calculation that needs to be displayed on the gsp page tag is the right place for that.

Another way to send data into grails is via attrs map. Each tag is specified in the file ending with TagLib and the format of the tag is:

def messageBox = {attrs, body ->
out << render(template:"/templates/common/messageBoxTemplate", model:[title:attrs.title, body:body()])
}

So tag is closure with two variables: attrs and body. Using attrs you can access any custom data sent to the tag.

So how do we send that data?

When displaying tag from the gsp page you are using construct like this one:

<g:messageBox title="Register, it takes only seconds">

In this case the title is custom data sent to the tag.

To execute given tag from the controller or some other groovy code you can use construct like this one:

g.messageBox(title:"Register, it takes only seconds") {
//body to be displayed
}

So for example, to display number of registered users on the grails and groovy tutorials page I am using direct access to database from the tag and then sending those data to the model. But I could also create e.g. application scoped variable for this and gain some performance. So currently the code in the tag looks like this:

def dataInfo = {attrs, body ->
def postsCount = TutorialLink.count()
def userCount = User.count()
out << render(template:"/templates/common/statsTemplate", model:[userCount:userCount, postsCount:postsCount])
}