Luc Dewavrin's weblog

Mimic Facelet Layouts in Grails

| Comments

I wanted to mimic facelets <ui:insert /> and <ui:define /> tags in grails.I find facelets to be quite powerful because it allows to define a fragment in your template that can be redefined by the view, otherwise a default fragment is displayed.It can be useful for instance for a menu where you want all views to use a default menu and some use another menu.

In facelets, you would create a template file and add a <ui:insert /> statement for the menu, like this:

1
2
3
<ui:insert name="menu">
    <ui:include src="../frags/menu.xhtml" />
</ui:insert>

Here the <ui:insert/> statement by default includes with the help of the <ui:include/>element a menu fragment (a partial page).

In your view you could if wanted redefine the menu with the <ui:define/> element, like this:

1
2
3
<ui:composition template="layout/template.xhtml">
  <ui:define name="menu" />
</ui:composition>
Override default menu here

Grails template system is handled by sitemesh. To achieve the same goal, you can in your template file (layout/main.gsp for instance), add the following element for the menu :

1
<g:pageproperty name="page.menu" default="${render(template:'/frags/menu')}" />

It achieves the same purpose, actually instead of defining a page section like in facelets, it displays the calling page’s <content> element named menu if present (control is inverted but the result is the same).Otherwise, if the <content> element is not found, the menu fragment is rendered.The fragment page should be in our example created in the frags directory under the name _menu.gsp. In your view, you can therefore define the menu section of your template by declaring a content element.

1
2
3
4
5
6
7
8
9
10
11
12
13
<html>
   <head>
     <meta http-equiv="Content-Type" content="text/html; charset=UTF-8" />
     <meta name="layout" content="main" />
     <title>Show Book</title>
  </head>
  <body>
     <content tag="menu">
        <div>Override default menu here</div>
     </content>
     <!-- More content here -->
   </body>
</html>

Comments