mscharhag, Programming and Stuff;

A blog about programming and software development topics, mostly focused on Java technologies including Java EE, Spring and Grails.

Sunday, 8 September, 2013

Grails: Using templates instead of Taglibs for rendering Views

Assume we want to render a small box in HTML which can be closed with a button and contains some kinds of content. We could start with something like this:

<div class='closeableBox'>
  <a class='closeButton' href='#'>close</a>
  <div class='content'>
    <ul>
      <li>first</li>
      <li>second</li>
    </ul>
  </div>
</div>

The content in this case is a simple list with two elements. However, we might want to use the box with the close button later for showing some other content. Obviously we don't want to repeat the code for the box in this case. The Grails way for doing this would be to write a TagLib function for this:

class MyTagLib {
  
  static namespace = "my"

  def closeableBox = { attrs, body ->
    out <<   """ 
      <div class='closeableBox'>
        <a class='closeButton' href='#'>close</a>
        <div class='content'>
          ${ body() }
        </div>
      </div>
    """
  }
}

This tag could be used in the following way:

<my:closeableBox>
  <ul>
    <li>first</li>
    <li>second</li>
  </ul>
</my:closeableBox>

Even with Groovy's multiline strings the mix of HTML and Groovy code in the TagLib is very ugly.
To avoid HTML code within the TagLib the grails documentation suggests using a template:

def closeableBox = { attrs, body ->
  out << render(template: "closeableBox", model: [content: body()])
}

The HTML part is moved into a template named _closeableBox.gsp. The body content is passed by the model variable content. The template code is shown in the following snippet:

<div class='closeableBox'>
  <a class='closeButton' href='#'>close</a>
  <div class='content'>
    ${ content }
  </div>
</div>

This works fine. But wouldn't it be nice to do this without the TagLib function? There is indeed a way for doing this!

With the <g:render /> tag it is possible to include templates within a GSP page. This is generally useful for partitioning a view into multiple smaller parts. Our example template can be included in another GSP file with the following line:

<g:render template="closeableBox" model="${ [content: '...'] }" />

The content that should be displayed in our box can be passed by using the model attribute of the <g:render /> tag. The obvious problem is that this way of passing data is very unhandy for passing larger pieces of HTML code.

What the grails documentation doesn't tell you is that <g:render /> tags can have a body:

<g:render template="closeableBox">
  <ul>
    <li>first</li>
    <li>second</li>
  </ul>
</g:render>

To render the body content in our template we can use the (unfortunately undocumented) body() function like in the TagLib. So, we have to modify the template like this:

<div class='closeableBox'>
  <a class='closeButton' href='#'>close</a>
  <div class='content'>
    ${ body() }
  </div>
</div>

Finaly we no longer need the TagLib function for embedding body content to templates.

An alternative way of rendering the template is using the tmpl namespace provided by Grails:

<tmpl:closeableBox>
  <ul>
    <li>first</li>
    <li>second</li>
  </ul>
</tmpl:closeableBox>

This way also supports body content and is an equivalent solution to using the <g:render > tag.

Comments

  • Aiden Zhao - Wednesday, 11 November, 2015

    Thanks! Interesting and useful comparison.

  • Ben - Wednesday, 9 December, 2015

    Thanks!

  • Tomas - Monday, 21 December, 2015

    In grails 3.0.9, this approach renders the body in quotations mark causing instead of input field, "<input...>" is displayed...
    Do you know how to avoid this?

Leave a reply