Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Thymeleaf recursion not working

Tags:

html

thymeleaf

I'm trying to create a recursive list using Thymeleaf. I'm using a simple Java object to model a node which has has two fields, a description and then an array list of child nodes. I'm using the following HTML/Thymeleaf to process the structure but it isn't recursively iterating through to the next level down.

My Java code looks as follows:

public class Node {
    public String description;
    public ArrayList<Node> children;
}

My Thymeleaf/HTML code is as follows:

<html>
    ...
    <body>
        <div th:fragment="fragment_node" th:remove="tag">
            <ul th:if="${not #lists.isEmpty(node.children)}" >
                <li th:each="child : ${node.children}"
                    th:text="${child.description}"
                    th:with="node = ${child}"
                    th:include="this::fragment_node">List Item</li>
            </ul>
        </div>

    </body>
</html>

If my data structure looks as follows:

  • Main node 1
    • Child node 1
    • Child node 2
  • Main node 2
    • Child node 3
    • Child node 4

I'd expect to get:

<ul>
    <li>Main Node 1</li>
    <li>
        <ul>
            <li>Child node 1</li>
            <li>Child node 2</li>
        </ul>
    </li>
    <li>Main Node 2</li>
    <li>
        <ul>
            <li>Child node 3</li>
            <li>Child node 4</li>
        </ul>
    </li>
</ul>

However, I only get:

<ul>
    <li>Main Node 1</li>
    <li>Main Node 2</li>
</ul>

Can anyone spot why this may not be working?

like image 506
daryl Avatar asked Jun 17 '26 09:06

daryl


1 Answers

The cause of the problem is

You are trying to th:text and trying to add the description to a <li> as well as you are trying to th:include the fragment inside the same tag <li>.

Your th:include is replaced by the th:text as th:text is processed with priority by default.

Direct solution to your source code

 .....
 <li th:each="child : ${node.children}" th:inline="text" th:with="node = ${child}">
      [[${child.description}]]
      <ul th:replace="this::fragment_node">List Item</ul>
 </li>
 .....

Even thought the above will work as you want, personally I find some design issues in your thymeleaf page.

Better solution using fragment parameters

 ...
 <ul th:fragment="fragment_node(node)" th:unless="${#lists.isEmpty(node.children)}" >
     <li th:each="child : ${node.children}" th:inline="text">
         [[${child.description}]]
         <ul th:replace="this::fragment_node(${child})"></ul>
     </li>
 </ul>
 ...
like image 69
Faraj Farook Avatar answered Jun 20 '26 02:06

Faraj Farook



Donate For Us

If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!