Search code examples
thymeleaf

Conditional Thymeleaf fragments


I would like to create a list of up to three items using a template fragment. Three spaces for items will always be displayed regardless of whether or not there is an item, so it looks something like this.

<div>
  <div th:if="${#lists.size(block.children) > 0}"
    th:insert="code-block :: block(${block.children[0]})" 
    th:remove="tag">
  </div>
</div>;
<div>
  <div th:if="${#lists.size(block.children) > 1}"
    th:insert="code-block :: block(${block.children[1]})" 
    th:remove="tag">
  </div>
</div>;
<div>
  <div th:if="${#lists.size(block.children) > 2}"
    th:insert="code-block :: block(${block.children[2]})" 
    th:remove="tag">
  </div>
</div>

However, even though the th:if statement evaluates as false with an empty list, it still attempts to execute the `th:include statement, giving me the following error:

Caused by: org.springframework.expression.spel.SpelEvaluationException:
EL1025E:(pos 14): The collection has '0' elements, index '0' is invalid

How can I get the if statement to take precedence over the fragment execution?


Solution

  • Yeah, unfortunately since include has precedence over if, you're going to have to move the if higher up. The simplest way would be to put it in a th:block, like this:

    <div>
      <th:block th:if="${#lists.size(block.children) > 0}">
        <div th:insert="code-block :: block(${block.children[0]})" th:remove="tag" />
      </th:block>
    </div>;
    <div>
      <th:block th:if="${#lists.size(block.children) > 1}">
        <div th:insert="code-block :: block(${block.children[1]})" th:remove="tag" />
      </th:block>
    </div>;
    <div>
      <th:block th:if="${#lists.size(block.children) > 2}">
        <div th:insert="code-block :: block(${block.children[2]})" th:remove="tag" />
      </th:block>
    </div>
    

    You could also probably simplify your code to look something more like this:

    <th:block th:each="i: ${#numbers.sequence(0, 2)}">
      <th:block th:if="${#lists.size(block.children) > i}">
        <div th:insert="code-block :: block(${block.children[i]})" th:remove="tag" />
      </th:block>
    
      <th:block th:unless="${i == 2}">;</th:block>
    </th:block>