Creating Layouts
Grails leverages
Sitemesh, a decorator engine, to support view layouts. Layouts are located in the
grails-app/views/layouts
directory. A typical layout can be seen below:
<html>
<head>
<title><g:layoutTitle default="An example decorator" /></title>
<g:layoutHead />
</head>
<body onload="${pageProperty(name:'body.onload')}">
<div class="menu"></menu>
<div class="body">
<g:layoutBody />
</div>
</div>
</body>
</html>
The key elements are the
layoutHead,
layoutTitle and
layoutBody tag usages, here is what they do:
layoutTitle
- outputs the target page's title
layoutHead
- outputs the target pages head tag contents
layoutBody
- outputs the target pages body tag contents
The previous example also demonstrates the
pageProperty tag which can be used to inspect and return aspects of the target page.
Triggering Layouts
There are a few ways to trigger a layout. The simplest is to add a meta tag to the view:
<html>
<head>
<title>An Example Page</title>
<meta name="layout" content="main"></meta>
</head>
<body>This is my content!</body>
</html>
In this case a layout called
grails-app/views/layouts/main.gsp
will be used to layout the page. If we were to use the layout from the previous section the output would resemble the below:
<html>
<head>
<title>An Example Page</title>
</head>
<body onload="">
<div class="menu"></div>
<div class="body">
This is my content!
</div>
</body>
</html>
Specifying A Layout In A Controller
Another way to specify a layout is to specify the name of the layout by assigning a value to the "layout" property in a controller. For example, if you have a controller such as:
class BookController {
static layout = 'customer' def list = { … }
}
You can create a layout called
grails-app/views/layouts/customer.gsp
which will be applied to all views that the
BookController
delegates to. The value of the "layout" property may contain a directory structure relative to the
grails-app/views/layouts/
directory. For example:
class BookController {
static layout = 'custom/customer' def list = { … }
}
Views rendered from that controller would be decorated with the
grails-app/views/layouts/custom/customer.gsp
template.
Layout by Convention
Another way to associate layouts is to use "layout by convention". For example, if you have a controller such as:
class BookController {
def list = { … }
}
You can create a layout called
grails-app/views/layouts/book.gsp
, by convention, which will be applied to all views that the
BookController
delegates to.
Alternatively, you can create a layout called
grails-app/views/layouts/book/list.gsp
which will only be applied to the
list
action within the
BookController
.
If you have both the above mentioned layouts in place the layout specific to the action will take precedence when the list action is executed.
Inline Layouts
Grails' also supports Sitemesh's concept of inline layouts with the
applyLayout tag. The
applyLayout
tag can be used to apply a layout to a template, URL or arbitrary section of content. Essentially, this allows to even further modularize your view structure by "decorating" your template includes.
Some examples of usage can be seen below:
<g:applyLayout name="myLayout" template="bookTemplate" collection="${books}" /><g:applyLayout name="myLayout" url="http://www.google.com" /><g:applyLayout name="myLayout">
The content to apply a layout to
</g:applyLayout>
Server-Side Includes
While the
applyLayout tag is useful for applying layouts to external content, if you simply want to include external content in the current page you can do so with the
include:
<g:include controller="book" action="list"></g:include>
You can even combine the
include tag and the
applyLayout tag for added flexibility:
<g:applyLayout name="myLayout">
<g:include controller="book" action="list"></g:include>
</g:applyLayout>
Finally, you can also call the
include tag from a controller or tag library as a method:
def content = include(controller:"book", action:"list")
The resulting content will be provided via the return value of the
include tag.