thymeleaf and condition and list size - thymeleaf

I use thymeleaf 3 and I try to use an "and" in a condition and use the size of a list in the condition
<div th:if="${param.isGenerated and #lists.size(param.options) lt 1}" th:remove="tag">
<label th:text="${param.value}"></label>
</div>
I get this error
org.attoparser.ParseException: Exception evaluating SpringEL
expression:

try
${param.isGenerated and #lists.isEmpty(param.options)}

Related

Thymeleaf - getting locale and comparing

The below should set h1 to HOWDY as the locale is showing en_GB, but it doesn't fall into the case?
Am I doing something wrong here? Thanks
<h1 th:text="${#locale}"></h1>
<div th:switch="${#locale}">
<h1 th:case="'en_GB'">HOWDY</h1>
</div>
When you use Thymeleaf's #locale, you are using a reference to a Java Locale object.
What Works?
The following works the way you expect, because it has already evaluated the Java locale object to its string representation, before evaluating each case statement:
<div th:switch="${#locale.toString()}">
<h1 th:case="'en_GB'">HOWDY</h1>
</div>
The following also works:
<div th:switch="__${#locale}__">
<h1 th:case="'en_GB'">HOWDY</h1>
</div>
In this case, it works because you are using the Thymeleaf preprocessor syntax __${...}__ to force Thymeleaf to evaluate #locale (to its string representation) before it evaluates the remainder of the switch statement.
Additional Explanation
Because Thymeleaf's #locale represents a Java Locale object, you can use any of Locales suitable fields and methods, such as :
<div th:text="${#locale.country}"></div> <!-- a field -->
<div th:text="${#locale.toLanguageTag()}"></div> <!-- a method -->
This is why only using ${#locale} in the Thymeleaf switch statement does not match the 'en_GB' string literal that you are expecting it to match: Thymeleaf is comparing an object to a string.
When you use this...
<div th:text="${#locale}"></div>
...you are again accessing the object itself. But in this case the object will use its toString() method when being rendered by Thymeleaf, before it is displayed - giving you your en_GB displayed value.
However, when you use this...
<div th:switch="${#locale}">
<h1 th:case="'en_GB'">HOWDY</h1>
</div>
...Thymeleaf is using the locale object in the switch statement, not its string representation.

How to apply elvis operator in Thymeleaf?

how to apply a ternary condition that Elvis Operator in Thymeleaf.
I tried this but there is an error showing in IDE. the error Tag start is not closed
<div th:utext="${ed.aurl} ? '<button th:href="#{ed.aurl}" target="_blank" download>View Attachment </button>' : 'No Attachment' "></div>
You shouldn't/can't use HTML in attributes like that (it's expecting a valid HTML doc)... why not write this as regular HTML?
<div>
<button th:if="${ed.aurl}" th:href="#{ed.aurl}" target="_blank" download>View Attachment</button>
<span th:unless="${ed.aurl}">No Attachment</span>
</div>

Thymeleaf - How to write Html string literals?

How can we write HTML and string literals at a same time in Thymeleaf ?
<div class="details"><span class="Section" th:utext="'Sec' <br> ${wind.sec}"></span><span class="Axiom" th:utext="'Axiom' <br> ${wind.axiom}"></span></div>
This throws error
Cannot execute GREATER THAN from Expression "('Sec' < br) > ${wind.sec}". Left is "true", right is "Great"
You can use the following = which uses + for string concatenation:
<div class="details">
<span class="Section" th:utext="'Sec<br>' + ${wind.sec}"></span>
<span class="Axiom" th:utext="'Axiom<br>' + ${wind.axiom}"></span>
</div>
The <br> is just part of the text literal in this case - because you are using th:utext.
However, using unescaped values such as ${wind.sec} is unsafe and is not recommended. There could be harmful values in that variable - especially if the variable holds data provided by end users.
So, unless the following structure change poses a problem, I would recommend something like this:
<div class="details">
<span class="Section" th:utext="'Sec<br>'"></span>
<span class="Section" th:text="${wind.sec}"></span>
<span class="Axiom" th:utext="'Axiom<br>'"></span>
<span class="Axiom" th:text="${wind.axiom}"></span>
</div>
Here we have separated the true text literals (which can use th:utext) from the variables (which should use th:text). Now, any HTML which may have found its way into your ${...} variables will be escaped, rendering it harmless.

default else statement for thymeleaf if case

I know I can use th:if and th:unless for if-else condition on thymeleaf. But i am wondering if there are any other way to handle default else without using th:unless.
i have if condition like this
th:if="${not #lists.isEmpty(myList) and condition1 and condition2 and condition3}"
now i don't want to repeat same conditions on th:unless block. Is there is way to do this without using th:unless?
Nope, no way to do that with th:if -- it affects a single tag only. There are a couple of more verbose options though:
Use th:with for your conditions. For example:
<th:block th:with="condition=${not #lists.isEmpty(myList) and condition1 and condition2 and condition3}">
<div th:if="${condition}" />
<div th:unless="${condition}" />
</th:block>
Use th:switch. For example:
<th:block th:switch="${not #lists.isEmpty(myList) and condition1 and condition2 and condition3}">
<div th:case="true" />
<div th:case="*" />
</th:block>

Select unique set of nodes with XPath?

I want to select a set of elements as nodes (the content of div[#class="Adres"]):
<div class="KolumnaStyl">
<div class="Nazwa">ABCD</div>
<div class="Adres">
12-345 Warszawa
<br/>
ul. Krasnobrodzka 5
<br/>
Mazowieckie
This can be done with:
//div[#class="KolumnaStyl"]/div[#class="Adres"]/node()
As it happens, there are two identical div[#class="Adres"] on the page, which means that node() currently selects the content of both of them. I can't, however, call //div[#class="KolumnaStyl"][1] - that doesn't select the first occurrence.
How can I select a unique set of nodes if the parent directory exists multiple times?
Take a look at "XPath Get first element of subset".
Basically, predicates have higher precedence than the / and // operators.
So, (//div[#class="KolumnaStyl"]//(div[#class="Adres"]))[1] should return your desired result.
Also check out the spec for more background info.
If you want the first matched one, then do :
(//div[#class="KolumnaStyl"]//div[#class="Adres"])[1]/node()
In XPATH first means 1, not 0.
Here is a sample HTML :
<body>
<div class="foo">
<p> 12 </p>
</div>
<div class="foo">
<p> 112 </p>
</div>
</body>
XPATH expression:
(//div[#class = 'foo'])[1]
output
<div class="foo">
<p>12</p>
</div>

Resources