170

What's the best way to do a simple if-else in Thymeleaf?

I want to achieve in Thymeleaf the same effect as

<c:choose>
  <c:when test="${potentially_complex_expression}">
     <h2>Hello!</h2>
  </c:when>
  <c:otherwise>
     <span class="xxx">Something else</span>
  </c:otherwise>
</c:choose>

in JSTL.

What I've figured so far:

<div th:with="condition=${potentially_complex_expression}" th:remove="tag">
    <h2 th:if="${condition}">Hello!</h2>
    <span th:unless="${condition}" class="xxx">Something else</span>
</div>

I don't want to evaluate potentially_complex_expression twice. That's why I introduced local variable condition. Still I don't like using both th:if="${condition} and th:unless="${condition}".

An important thing is that I use two different HTML tags: let's say h2 and span.

Can you suggest a better way to achieve it?

Sae1962
  • 1,122
  • 15
  • 31
Maciej Ziarko
  • 11,494
  • 13
  • 48
  • 69

14 Answers14

256

Thymeleaf has an equivalent to <c:choose> and <c:when>: the th:switch and th:case attributes introduced in Thymeleaf 2.0.

They work as you'd expect, using * for the default case:

<div th:switch="${user.role}"> 
  <p th:case="'admin'">User is an administrator</p>
  <p th:case="#{roles.manager}">User is a manager</p>
  <p th:case="*">User is some other thing</p> 
</div>

See this for a quick explanation of syntax (or the Thymeleaf tutorials).

Disclaimer: As required by StackOverflow rules, I'm the author of Thymeleaf.

Sae1962
  • 1,122
  • 15
  • 31
Daniel Fernández
  • 7,335
  • 2
  • 30
  • 33
  • ok but..how do i invoke a javascript based on the type of customer(i.e anonymous or logged in)... – Lucky Jan 02 '13 at 11:38
  • 1
    See the chapter on "Text inlining", specifically the "JavaScript inlining" section at the "Using Thymeleaf" tutorial in http://www.thymeleaf.org/documentation.html – Daniel Fernández Jan 02 '13 at 12:12
  • And how can I do th:switch on an iterator.index value? I want to do a set of cases when the value is <5, and switch to default case if value is >5 – Loser Coder Oct 10 '14 at 00:33
  • 1
    @DanielFernández: can you please help me with https://stackoverflow.com/questions/48499723/thymeleaf-list-within-list-input . I couldn't tag you on the question directly. Really stuck. – jetty Feb 23 '18 at 08:24
  • The original question was asking about a boolean condition. How would you do that with `switch`? Would you make the first case be `th:case="true"`? – GreenGiant Jun 29 '23 at 20:41
133

I tried this code to find out if a customer is logged in or anonymous. I did using the th:if and th:unless conditional expressions. Pretty simple way to do it.

<!-- IF CUSTOMER IS ANONYMOUS -->
<div th:if="${customer.anonymous}">
   <div>Welcome, Guest</div>
</div>
<!-- ELSE -->
<div th:unless="${customer.anonymous}">
   <div th:text=" 'Hi,' + ${customer.name}">Hi, User</div>
</div>
Mahozad
  • 18,032
  • 13
  • 118
  • 133
Lucky
  • 16,787
  • 19
  • 117
  • 151
  • 12
    This doesn't answer the OP's question because that was about avoiding duplicating complex expressions. And like other solutions, this breaks the "natural templates" idea, which is a major selling-point of Thymeleaf. Not sure what to do about it myself, but just wanted to point it out in case someone has an answer. – Stephen Harrison Oct 05 '14 at 15:04
  • @Lucky this gives me an error EL1007E:(pos 0): Property or field 'Status' cannot be found – JayC Dec 05 '16 at 17:43
  • @Jackie In the above example customer is an object and anonymous is a boolean field in the Customer class. Make sure your object is not null and field name is correct. – Lucky Dec 06 '16 at 05:45
34

I'd like to share my example related to security in addition to Daniel Fernández.

<div th:switch="${#authentication}? ${#authorization.expression('isAuthenticated()')} : ${false}">
    <span th:case="${false}">User is not logged in</span>
    <span th:case="${true}">Logged in user</span>
    <span th:case="*">Should never happen, but who knows...</span>
</div>

Here is complex expression with mixed 'authentication' and 'authorization' utility objects which produces 'true/false' result for thymeleaf template code.

The 'authentication' and 'authorization' utility objects came from thymeleaf extras springsecurity3 library. When 'authentication' object is not available OR authorization.expression('isAuthenticated()') evaluates to 'false', expression returns ${false}, otherwise ${true}.

Mahozad
  • 18,032
  • 13
  • 118
  • 133
blandger
  • 718
  • 7
  • 17
  • That's a good tip, but note that you can use `true` and `false` literals—you don't need to use variable substitution expressions for them. See also [Yatendra's answer](https://stackoverflow.com/a/61764312/421049). – Garret Wilson Aug 28 '20 at 15:23
22

You can use

If-then-else:  (if) ? (then) : (else)

Example:

'User is of type ' + (${user.isAdmin()} ? 'Administrator' : (${user.type} ?: 'Unknown'))

It could be useful for the new people asking the same question.

Lucky
  • 16,787
  • 19
  • 117
  • 151
Jad B.
  • 1,403
  • 15
  • 14
16

Another solution - you can use local variable:

<div th:with="expr_result = ${potentially_complex_expression}">
    <div th:if="${expr_result}">
        <h2>Hello!</h2>
    </div>
    <div th:unless="${expr_result}">
        <span class="xxx">Something else</span>
    </div>
</div>

More about local variables:
http://www.thymeleaf.org/doc/tutorials/2.1/usingthymeleaf.html#local-variables

Mahozad
  • 18,032
  • 13
  • 118
  • 133
jareks
  • 643
  • 1
  • 10
  • 14
  • I think you have added an extra "=" sign in your code. Please verify it again and correct it if I'm right. – Lucky Oct 19 '15 at 17:27
  • In my opinion code is ok. I do not know which extra '=' sign you mean. – jareks Oct 21 '15 at 09:17
  • Yea the code is ok. Sorry, I confused it with the `th:each` where the expression has `:` instead of `=` – Lucky Oct 21 '15 at 09:23
  • But this answer is very close to my solution. While doing the th:with expression seems redundant to me. Basically this solution uses th:if and th:unless conditional statements. – Lucky Oct 21 '15 at 09:30
  • I think it's not redundant. If you use only th:if and th:unless complex expression would be executed twice... – jareks Oct 21 '15 at 10:43
  • Yes, if you had read the question clearly, the OP has already tried the same code as you have provided in your solution as he also uses the same th:with expression block. – Lucky Oct 21 '15 at 10:51
  • You should be using th:block instead of div when the only purpose is to introduce variable(s). – Nicolai Ehemann Mar 16 '18 at 13:35
11

In simpler case (when html tags is the same):

<h2 th:text="${potentially_complex_expression} ? 'Hello' : 'Something else'">/h2>
Grigory Kislin
  • 16,647
  • 10
  • 125
  • 197
  • Do you know how to add translations for 'Hello' and 'Something else' in this expression? – Laura Jun 30 '17 at 14:22
  • @Laura You can use internationalization and load different language translations based on location from properties file. See https://looksok.wordpress.com/tag/internationalization/ , http://www.marcelustrojahn.com/2016/12/springboot-thymeleaf-i18n-internationalization/ – Lucky Jul 14 '17 at 06:41
  • Quoting the question: "An important thing is that I use two different HTML tags: let's say `h2` and `span`." – Egor Hans Mar 04 '21 at 08:19
10

Use th:switch as an if-else

<span th:switch="${isThisTrue}">
  <i th:case="true" class="fas fa-check green-text"></i>
  <i th:case="false" class="fas fa-times red-text"></i>
</span>

Use th:switch as a switch

<span th:switch="${fruit}">
  <i th:case="Apple" class="fas fa-check red-text"></i>
  <i th:case="Orange" class="fas fa-times orange-text"></i>
  <i th:case="*" class="fas fa-times yellow-text"></i>
</span>
Amit
  • 33,847
  • 91
  • 226
  • 299
7

Another solution is just using not to get the opposite negation:

<h2 th:if="${potentially_complex_expression}">Hello!</h2>
<span class="xxx" th:if="${not potentially_complex_expression}">Something else</span>

As explained in the documentation, it's the same thing as using th:unless. As other answers have explained:

Also, th:if has an inverse attribute, th:unless, which we could have used in the previous example instead of using a not inside the OGNL expression

Using not also works, but IMHO it is more readable to use th:unless instead of negating the condition with not.

riddle_me_this
  • 8,575
  • 10
  • 55
  • 80
Pau
  • 14,917
  • 14
  • 67
  • 94
2
<div th:switch="${user.role}"> 
<p th:case="'admin'">User is an administrator</p>
<p th:case="#{roles.manager}">User is a manager</p>
<p th:case="*">User is some other thing</p> 
</div>


<div th:with="condition=${potentially_complex_expression}" th:remove="tag">
<h2 th:if="${condition}">Hello!</h2>
<span th:unless="${condition}" class="xxx">Something else</span>
</div>
Vikki
  • 1,897
  • 1
  • 17
  • 24
1
<div style="width:100%">
<span th:each="i : ${#numbers.sequence(1, 3)}">
<span th:if="${i == curpage}">
<a href="/listEmployee/${i}" class="btn btn-success custom-width" th:text="${i}"></a
</span>
<span th:unless="${i == curpage}">
<a href="/listEmployee/${i}" class="btn btn-danger custom-width" th:text="${i}"></a> 
</span>
</span>
</div>

enter image description here

1

This works for me when I wanted to show a photo depending on the gender of the user:

<img th:src="${generou}=='Femenino' ? @{/images/user_mujer.jpg}: @{/images/user.jpg}" alt="AdminLTE Logo" class="brand-image img-circle elevation-3">
Partho63
  • 3,117
  • 2
  • 21
  • 39
Italo Oré
  • 67
  • 4
1

If-then-else have 2 variant.

First:

<form method="get" th:action="@{/{id}(id=${user.isAdmin()}?'admin':'user')}">
    <input type="submit" value="to Main"/>
</form>

Second:

<th:block th:if!="${branchMessages.isEmpty()}">
    ...
</th:block>
<th:block th:unless="${branchMessages.isEmpty()}">
    ...
</th:block>
Partho63
  • 3,117
  • 2
  • 21
  • 39
gapserg
  • 11
  • 2
1
<div th:switch="true"> 
    <div th:case="${condition}=='1'">answer1...</div>
    <div th:case="${condition}=='2'">answer2...</div>
    <div th:case="*">answer3...</div> 
</div>
戴勝台
  • 11
  • 1
  • 1
    Hey, thanks for joining and contribution. At StackOverflow, you're encouraged to explain the answer, and not just provide a snippet. – f.khantsis Oct 18 '22 at 18:10
0

If and unless sometimes fail to provide the expected result when using 2 separated blocks. If and else can also be achieved by using if statement in the first block for condition 1 (TRUE) and the second if statement is the second block for alternative choice when the first condition fails (FALSE).

Hoping that this will help.

<div th:with="condition=${potentially_complex_expression}" th:remove="tag">
   //True
   <h2 th:if="${if_condition}">Hello!</h2>

   //False
   <h2 th:if="${alternative_for_false}">Something else</h2>
</div>