Search code examples
spring-bootthymeleafspring-el

Thymeleaf with recursive fragment for menus


I am trying to create a recursive fragment in Thymeleaf to produce a left-side menu. Core architecture is Spring Boot, and I am passing in a populated Menu object that has children and such. Code for the Menu looks like:

public class MenuItem {
    private String displayLabel;
    private String actionUri;

    private List<MenuItem> children;

    // ...getters/setters/etc...
}

And a Thymeleaf fragment defined like:

<!DOCTYPE HTML>
<html xmlns:th="http://www.thymeleaf.org">
<head>
<title>Menu</title>
<meta http-equiv="Content-Type" content="text/html; charset=UTF-8" />
</head>
<body>
    <div th:fragment="submenu (menu)" th:remove="tag">
        <ul th:if="${not #lists.isEmpty(menu.children)}" th:class="${#objects.nullSafe(depth, 1) &gt; 1}? 'children'">
            <li th:each="child : ${menu.children}">
                <span th:if="${#strings.isEmpty(child.actionUri)}" th:text="${child.displayLabel}">Addons</span>
                <a th:if="${not #strings.isEmpty(child.actionUri)}" th:href="${child.actionUri}" th:text="${child.displayLabel}">Link Item</a>
                <div th:replace="fragments/submenu :: submenu(menu=${child}, depth=depth+1)" th:remove="tag" />
            </li>
        </ul>
    </div>
</body>
</html>

If I take the depth code out, everything seems to work fine. But with it I get:

2014-07-30 11:13:00.832 ERROR 45869 --- [nio-8080-exec-4] o.a.c.c.C.[.[.[/].[dispatcherServlet]    : Servlet.service() for servlet [dispatcherServlet] in context with path [] threw exception [Request processing failed; nested exception is org.thymeleaf.exceptions.TemplateProcessingException: Exception evaluating SpringEL expression: "#objects.nullSafe(depth, 1) > 1" (fragments/submenu:9)] with root cause

java.lang.ClassCastException: java.lang.Integer cannot be cast to java.lang.String

The purpose of the depth code is so I can optionally put in a class to track when menu items are children of the parent. Is it possible to either fix the depth counter or to do something else to test if the fragment was ran already? Ultimately I just want a recursive menu with the top ul having no class and the child uls having a class of children.


Solution

  • Try these changes

    1.Use two parameters in fragment as

    <div th:fragment="submenu (menu, depth)" >
    

    2.Pass the depth as

    <div th:replace="fragments/submenu :: submenu(menu=${child}, depth=${depth+1})"  />