Tobías
Tobías

Reputation: 6297

Include a fragment from the same thymeleaf template using "this :: content" or ":: content" not working as expected

I'm including a template fragment from the same template file. Section "8.1 Including template fragments - Defining and referencing fragments" of the docs states that:

"::domselector" or "this::domselector" Includes a fragment from the same template.

If I haven't misunderstood, I should be able to reference the fragment as follows: th:include="this :: contentB" or th:include=":: contentB" but only making full reference th:include="test-fragment :: contentB" works for me.

This is the sample code:

HomeController.java

@Controller
class HomeController {
  @RequestMapping({ "/", "index", "home" })
  String index(Model model) {
    return "test";
  }
}

test.html

<!DOCTYPE html>
<html>
  <head></head>
  <body>
    <ul th:replace="test-fragment :: contentA" />
  </body>
</html>

test-fragment.html

<!DOCTYPE html>
<html>
  <head></head>
  <body>
    <ul th:fragment="contentA">
      <li th:each="idx : ${#numbers.sequence(1,4)}" th:switch="${idx}">

        <th:block th:case="1" 
            th:include="test-fragment :: contentB" 
            th:with="strVar = 'One'"/>

        <th:block th:case="2" 
            th:include="this :: contentB"
            th:with="strVar = 'Two'"/>

        <th:block th:case="3" 
            th:include=" :: contentB"
            th:with="strVar = 'Three'"/>

        <th:block th:case="*" 
            th:include="/test-fragment :: contentB" 
            th:with="strVar = 'Other'"/>
      </li>
    </ul>

    <span th:fragment="contentB">
      <span th:text="|value: ${strVar}|" />
    </span>
  </body>
</html>

Output is:

<!DOCTYPE html>
<html>
   <head></head>
   <body>
      <ul>
         <li><span>value: One</span></li>
         <li></li>
         <li></li>
         <li><span>value: Other</span></li>
      </ul>
   </body>
</html>

Case 2 and 3 are missing. What am I doing wrong?

I'm testing using Spring Boot 1.3.2.RELEASE

EDIT:

I've made a small test project to reproduce the issue, it can be found here: https://github.com/t-cst/thymeleaf-springboot-test

EDIT:

After some debug, I find out that when the fragment selector is "this :: contentB" or " :: contentB" then the template name is resolved as test instead of test-framgent. This is done at:

StandardFragment#extractFragment:189 from thymeleaf-2.1.4.RELEASE:

/* 186 */  String targetTemplateName = getTemplateName();
           if (targetTemplateName == null) {
               if (context != null && context instanceof Arguments) {
                   targetTemplateName = ((Arguments)context).getTemplateName();
/* 190 */      } else {
                   throw new TemplateProcessingException(
                           "In order to extract fragment from current template (templateName == null), processing context " +
                           "must be a non-null instance of the Arguments class (but is: " +
                           (context == null? null : context.getClass().getName()) + ")");
/* 195 */      }
           }

But I still don't know why this happens in my test.

EDIT:

I've also asked at thymeleaf forum. Maybe it's a bug. I've opened an issue.

Upvotes: 5

Views: 5186

Answers (1)

Tob&#237;as
Tob&#237;as

Reputation: 6297

In case someone ends here with the same issue, this is not possible in thymeleaf 2.1.4.RELEASE version, but it will be in next version 3.0

A comprehensive explanation can be found at this issue comment.

Upvotes: 3

Related Questions