In the last post we looked at plugging in Thymeleaf into a Spark Java application for view rendering. The concept was pretty simple: using the Thymeleaf engine, render a view with a map of variables to use as the model. But in reality, our applications need a bit more complexity. They need reusable layouts. In this post we'll take a look at how to handle that with Thymeleaf.
Reusable layouts include things like headers, footers, scripts and other things like nav menus that are common across the application. Thymeleaf accommodates these by using what they call "fragments" - reusable blocks of code defined by the
th:fragment attribute that can be called from your templates using the
th:include attributes. You can read all about it in their docs, but let's take a look at a practical example below.
To illustrate, let's create three separate fragments, one called
head.html, one called
nav.html and the final one called
foot.html. I've saved these in
/src/main/groovy/resources/templates/fragments. To make it more realistic, I've dropped in Bootstrap since that's what I'd usually do. Here is the simple code for each:
Now back in our Bootstrap class, in the main() method, I've created a Groovy closure to grab any 'common' model bits:
Then I modified the route for
/thymeleaf to include the
commonModel in the model I'm using to render that view:
And now it's just a matter of using the
th:replace attribute in my view wherever I'd like the fragments rendered:
Note that since my fragments were not in the
/templates directory, but a subdirectory called 'fragments', I had to pass the path from
/templates in the
th:replace attribute. Also notice that you can pass model variables to your fragment as I did on line 10. This is crucial for any layout system as layout bits are rarely purely static.
Compared to Sitemesh (which is what I'm used to in Grails) I think I'm a fan of the way Thymeleaf handles this. Something about Sitemesh always felt a little "backwards" (the layout includes the view) so I'm happy to see Thymeleaf approach it in a more "forward" manner (the view includes the layout bits).