When are Thymeleaf expression delimiters needed in Spring Boot?

Viewed 289

I'm using Spring Boot 2.3.3.RELEASE with Thymeleaf. From the Thymeleaf documentation it's not clear to me when I must use the ${} delimiters in a Thymeleaf expression.

For example I had this in my template, and it was working:

<div th:title="${doTest() ? 'foo' : 'bar'}" />

But then I reread the docs and I see that I could use this:

<div th:title="${doTest()} ? 'foo' : 'bar'" />

But the ? … : … ternary operator is an operator, so thus the whole thing is an expression. So why don't I need the ${} around the whole attribute value?

Could I also do this?

<div th:title="doTest() ? 'foo' : 'bar'" />

What about this?

<div th:title="'foo'" />

Why one and not the other?

What about this? Can I use just a bare true?

<div th:if="true">…</div>

Or do I need expression delimiters?

<div th:if="${true}">…</div>

Here's another example: I see this in the documentation:

<li th:text="${item.description}" …

But can I just use th:text="item.description"? What do the braces do for me?

I also see this:

th:each="item : ${items}"

Can I just use th:each="item : items" instead? Why wouldn't Thymeleaf know to evaluate items without the braces in ${items}?

Surely there must be some simple rule for when I need ${}, but it's not immediately obvious.

3 Answers

using an expression without ${} will be considered as a mix of values(strings, numbers booleans ...), operations and conditions, thus thymeleaf will try to execute the expression as it is. this is Thymeleaf Standard Expression engine

for example :

th:text="item.description" : will display item.description, the same if you do th:text="'item.description'" because thymeleaf looks at item.description as a text docs.

now using ${} with an expression, will be considered as variable expression meaning every literal token(text without '') is a variable that will be executed within a pre-defined Context.this is OGNL(Object-Graph Navigation Language)

in our example:

th:text="${item.description}": will display the description of the item object in the context. in spring you can register your object in the context using Model(or ModelAndView):
model.addAttribute("item", new Item()); this will throw an exception if no item is found in the context.

so th:text="${'item.description'}" and th:text="item.description" is the same but they are evaluated differently.

I think it's clear now that if you want to have access to objects( models, services, repositories...) from within your templates you should use ${}.

  • For example I had this in my template, and it was working:- Yes because this is executed by executed by OGNL(Object-Graph Navigation Language)
<div th:title="{$doTest() ? 'foo' : 'bar'}" />
  • But then I reread the docs and I see that I could use this:- Yes because this is executed by Thymeleaf Standard Expression engine.
<div th:title="{$doTest()} ? 'foo' : 'bar'" />
  • But the ? : an operator, so thus the whole thing is an expression. So why don't I need the ${} around the whole attribute value? - Because thymeleaf has Elvis Operator (?:) natively. So the Thymeleaf Standard Expression engine is able to execute it.

  • What about this? Can I use just a bare true?

    In Thymeleaf, any value can be evaluated to a boolean. We have a few values interpreted as false:

    • List item

    • null

    • the boolean value false

    • the number 0

    • the character \0

    • the strings “false”, “off”and “no”

Any other value is evaluated to true.

  • Here are some useful links :-

https://www.baeldung.com/spring-thymeleaf-conditionals

https://www.baeldung.com/thymeleaf-boolean

https://www.thymeleaf.org/doc/tutorials/2.1/usingthymeleaf.html#variables

http://commons.apache.org/ognl/

EDIT :-

<div th:title="{$doTest() ? 'foo' : 'bar'}" />

<div th:title="{$doTest()} ? 'foo' : 'bar'" />

You can use both the above syntax in your case. Both are executed differently but end result is same. First one is executed by OGNL and second one by Thymeleaf engine.

Your doubt was why the second one works? Why don't we need to put ?: operator inside ${}?

Answer to above questions is that Thymeleaf engine understands ?: operator natively. And it is called Elvis Operator. It similar to ternary opertaor we have in most programming languages but with minor differences. You can read more about it in the links i have shared.

Hence even if we don't put ?: inside ${} it is successfully executed by Thymeleaf Engine.

We use ${}, if we need to access a variable. Variable as in your example item.description, where item is an object/reference and description is a string inside the object item.

Assume that description has a value "This is thymeleaf".

Inorder to display the text in description on the html we implement in the following way :

<p th:text="${item.description}"></p>

Output:

This is thymeleaf

But using without the ${} expression, is going to yield the given string "item.description" itself on the html, that is the reference does not get resolved.

<p th:text="item.description"></p>

Output:

item.description

I would like to explain another example where there could be some exceptions, especially while using th:if and th:each.

Both the expressions below are the same and going to yield the same output :

<p th:if="${item.description} != null"></p>
<p th:if="${item.description != null}"></p>

The above expression says to display the paragraph if the description inside item is not null.

Thymeleaf expects us to use ${} so that if such an expression occurs then it can compare for the words inside the braces with the variables inside it's context and return the variable value if it finds a match.

Note : Thymeleaf maintains a context variable, accessible through #ctx which contains all the variables input to the template in the form of key value pairs.

If the variable is not enclosed with ${}, then it considers the string to be a plain text and uses them as it is.

Related