Skip to main content

Thymeleaf th:remove vs th:if Processors

Interestingly Makinus team encountered a scenario where the team has to choose between th:remove and th:if processors. The situation is like this. Makinus team worked on a project and the team lead suggested to go with #Thymeleaf template instead of decades old JSP. Hence it adopted Thymeleaf and Thymelead Layout framework to do layout-ing.

Thymeleaf Layout
Thymeleaf layout is a framework that helps doing the layout work just as tiles framework does it using JSP technology. The framework has 5 processors, important of which is layout:decorate. The processor layout:decorate works in the layout-content template model where the content template is a small piece of template that replaces content part of the layout template. This works as if parent/child templating mode where parent will define layout format while the child template replaces only the specified content portions.

Head Element Merging Strategy
Thymeleaf layout uses a special strategy to merge parent and child template <head></head> elements. This is special because it considers both parent and child template <head></head> elements while templating. But the other elements in the child template is not considered for layout-ing unless it has layout:fragment specified. The head element in the parent template can specify links and scripts for prototyping purpose while the child template can also specify the scripts and stylesheet links in the head element. So when it gets merged the layout parsed html has duplicate scripts and links in the html source.

Remove Duplicates From <head></head> Element
There are strategies to sort or group the <head></head> elements using layout template framework. But none of the strategies would work to remove duplicate <script></script> elements or <link/> elements. So the makinus team used th:if to conditionally parse the <script></script> and <link/> elements. The idea is, in the parent template the <script></script> and <link/> elements should specify th:if="false" always and in the child template the <script></script> and <link/> elements can be specified as it is. Because anyway the content template <head></head> elements would be considered for merging. This solution seems so ideal and removes duplicate <script></script> and <link/> elements from the parsed html. Thanks to th:if processor.

But its not the only way to remove duplicate <script></script> and <link/> elements. We have another approach to remove elements. That is, th:remove processor. This processor has quite a usefulness that it can entirely remove the element from being displayed in the html source. The values of th:remove processors are all, body, tag, all-but-first and none. Our solution is to remove duplicates entirely, hence th:remove="all" would fit into the solution. Makinus team chose the latter approach since th:remove has higher precedence than th:if, and would remove the tag element anyway. If th:if is used, and the value evaluates to true by mistake we end getting duplicates. So in order to avoid mistakes, makinus team went ahead with th:remove="all" approach. Thanks to th:remove processor.

Code Snippets

Approach 1 :-

layout.html
 <head>
   <th:block th:with="hide=false"/>

   <!--/* Bootstrap core CSS  */-->
   <link href="http://cdn.jsdelivr.net/webjars/bootstrap/3.3.7/css/bootstrap.min.css" 
           media="screen" rel="stylesheet" th:href="@{/webjars/bootstrap/3.3.7/css/bootstrap.min.css}" 
           th:if="${hide}"></link>

   <!--/*  Material Dashboard CSS   */-->
   <link href="/resources/css/material-dashboard.css" 
            media="screen" rel="stylesheet" th:href="@{/resources/css/material-dashboard.css}" 
            th:if="${hide}"></link>

   <!--/*     Fonts and icons    */-->
   <link href="http://maxcdn.bootstrapcdn.com/font-awesome/latest/css/font-awesome.min.css" 
            rel="stylesheet" th:if="${hide}"></link>
   <link href="http://fonts.googleapis.com/css?family=Roboto:400,700,300|Material+Icons" 
            rel="stylesheet" th:if="${hide}" type="text/css"></link>
 </head>

content.html
<head> 
    <link href="http://cdn.jsdelivr.net/webjars/bootstrap/3.3.7/css/bootstrap.min.css"
          th:href="@{/webjars/bootstrap/3.3.7/css/bootstrap.min.css}" rel="stylesheet" media="screen" />

    <link href="/resources/css/material-dashboard.css" th:href="@{/resources/css/material-dashboard.css}" 
           rel="stylesheet" media="screen" />

   <link href="http://maxcdn.bootstrapcdn.com/font-awesome/latest/css/font-awesome.min.css" 
          rel="stylesheet" >

    <link href='http://fonts.googleapis.com/css?family=Roboto:400,700,300|Material+Icons' 
          rel='stylesheet' type='text/css' >
</head> 


Approach 2 :-

layout.html
<head> 
    <!--/* Bootstrap core CSS  */-->
    <link href="http://cdn.jsdelivr.net/webjars/bootstrap/3.3.7/css/bootstrap.min.css"
          th:href="@{/webjars/bootstrap/3.3.7/css/bootstrap.min.css}" 
          rel="stylesheet" media="screen" th:remove="all"/>

    <!--/*  Material Dashboard CSS   */-->
    <link href="/resources/css/material-dashboard.css" th:href="@{/resources/css/material-dashboard.css}" 
          rel="stylesheet" media="screen" th:remove="all" />

    <!--/*     Fonts and icons    */-->
    <link href="http://maxcdn.bootstrapcdn.com/font-awesome/latest/css/font-awesome.min.css" 
          rel="stylesheet" th:remove="all" >
    <link href='http://fonts.googleapis.com/css?family=Roboto:400,700,300|Material+Icons' 
          rel='stylesheet' type='text/css' th:remove="all" >
</head>


content.html
<head> 
    <link href="http://cdn.jsdelivr.net/webjars/bootstrap/3.3.7/css/bootstrap.min.css"
          th:href="@{/webjars/bootstrap/3.3.7/css/bootstrap.min.css}" rel="stylesheet" media="screen" />

    <link href="/resources/css/material-dashboard.css" th:href="@{/resources/css/material-dashboard.css}" 
           rel="stylesheet" media="screen" />

   <link href="http://maxcdn.bootstrapcdn.com/font-awesome/latest/css/font-awesome.min.css" 
          rel="stylesheet" >

    <link href='http://fonts.googleapis.com/css?family=Roboto:400,700,300|Material+Icons' 
          rel='stylesheet' type='text/css' >
</head> 


Thymeleaf : 3.0.6.RELEASE 
Thymeleaf Layout: 2.2.2

Comments

Popular posts from this blog

CSRF enabled Ajax requests using Spring Security

Many of you who have worked on Spring Security might be aware of the fact that Spring Security protects applications from Cross Site Request Forgery using _csrf tokens in the request sent to the web server. You can find a detailed understanding in the Spring documentation page . The objective of this post is to explain how to send _csrf tokens in the Ajax requests when we protect our application URL and application access using spring security. How to get CSRF tokens While we submit a form using an application that is protected with Spring Security, the form gets a default hidden parameter in the form body when using <form:form> element. The param contains the _csrf tokens to authenticate the requests in the server. In case we use other ways to create forms, we have to manually include a hidden parameter that contains name as ${_csrf.parameterName} and  value as ${_csrf.token} . For example, <input type= "hidden" name= "${_csrf.parameterName}" ...

In-Place editing with X-Editable using Datatable plugin

Introduction In-place editing is a trending feature that can be seen in many latest web applications, a popular example would be trello.com where the editing data happens on the web page without any explicit forms or popups. Another such example I could point out is, thoughtplan.com. The in-place editing is very nice in such a way that editing data seems so natural and user friendly. To enable in-place editing, there are many free JQuery plugins available on the internet. We are discussing a very popular plugin called x-editable . Most of the time we use html tables to display data where in-place editing is enabled. Hence we need another plugin to elegantly display tables with enormous data. We use a famous JQuery plugin called datatable . Both of these plugins are used widely and free to use. Assumption      : Bootstrap 3, JQuery used Projects Integration In order to enable datatable features on any ordinary table found on web page, we should initialise datata...

A wonderful technique to reduce website development cost

Websites - Good way to get online presence Websites are very vital to get online presence of any business nowadays. Websites are categorized into two different types. First one is Static Website and second one is Dynamic Website, normally known as web applications. Static websites are most widely used for any business since they help to bring up the online presence more easily and quickly. Depending on the content and features, static websites cost around $300-$700 . It includes web design and development. Apart from that, the business has to spend for hosting space and domain name for the website. Cloud based development is now more prevalent. Building a website and running it will be very easy and cheap using these cloud infrastructure. But the difficulty facing the development of static websites still looms high as it does not matter who provides the infrastructure. The development cost is still same. Technology - LAMP Static websites are developed using HTML and PHP mostly...