Skip to content
Advertisement

How to change Thymeleaf fragments dynamically depending on the href link

I want to build a page with Thymeleaf fragments, which are rendered dynamically depending on the followed link.
And I have an issue with resolving fragments names in runtime through the Spring controller.

Here is the minimal reproductive example to show what I mean.


I have list.html page with two links List 1 and List 2 with pic and code as below:

Links

<body>
  <button type="button"><a th:href="${'/lists/list1'}">List 1</a></button>
  <button type="button"><a th:href="${'/lists/list2'}">List 2</a></button>

  <!-- This doesn't work, the include is not resolved correctly -->
  <th:block th:include="'fragments/lists/' + ${fragmentName}
                        + ' :: ' + ${fragmentName}"></th:block>

  <!-- However static include works well -->
  <th:block th:include="fragments/lists/list1 :: list1"></th:block>
</body>

The related Spring controller looks as:

@GetMapping("lists")
public String getListsPage(Model model) {
    model.addAttribute("fragmentName", "listAll");
    return "lists";
}

@GetMapping("lists/list1")
public String getAllItems(Model model) {
    model.addAttribute("list1", itemService.getList1());
    model.addAttribute("fragmentName", "list1");
    return "lists";
}

@GetMapping("lists/list2")
public String getAllItems(Model model) {
    model.addAttribute("list2", itemService.getList2());
    model.addAttribute("fragmentName", "list2");
    return "lists";
}

The problem that fragmentName is not being resolved at runtime and it throws TemplateInputException exception:

Caused by: org.thymeleaf.exceptions.TemplateInputException: Error resolving
  template ['fragments/lists/' + ${fragmentName} + '], template might not exist
  or might not be accessible by any of the configured Template Resolvers
  (template: "lists" - line 38, col 11)

At the same time static block works correctly as shown in list.html page code.

Please don’t suggest me Spring MVC 3.2 Thymeleaf Ajax Fragments, I don’t want to use AJAX, I found the current solution of returning the fragment name using controller very clear and simple for my case.

Probably I can use Fragment Expressions, but I am not sure how exactly.
Any suggestions are appreciated.

Advertisement

Answer

I would express the syntax like this:

<th:block th:include="~{${'fragments/lists/' + fragmentName} :: ${fragmentName}}"></th:block>
Advertisement