0
votes

I have an application with a standard page layout, and many content templates. Each content template could have one or more content sections that I want to treat as fragments. I'd like to be able to iterate over each fragment and include it separately after putting in formatting divs. The idea is that I don't want each content page to have to know how to nest section and div tags to get the page to format correctly. I've tried the following without success:

layout.html:

<html xmlns:th="http://www.thymeleaf.org"
      th:fragment="layout(contentFragments)">
<section class="row-outer-sm"
         th:each="frag,iterStat : ${contentFragments}">
    <div class="container">
        <div class="row justify-content-center">
            <div class="col">
                <div th:if="${iterStat.first}"
                         th:replace="fragments/messages :: messages">
                    Messages go here
                </div>
                <div th:replace="${frag}">
                   Content goes here.
                </div>
            </div>
        </div>
    </div>
</section>
</html>

content.html:

<html lang="en"
      xmlns:th="http://www.thymeleaf.org"
      th:replace="fragments/layout :: layout(~{:: div.section-content})">
<div class="section-content">
   Some things for my first section
</div>

<div class="section-content">
    Some things for my second section
</div>
</html>

The fragment expression in content.html correctly finds all the divs with the section-content class, but they appear to be passed into layout.html as a single concatenated fragment. Is there any way to get a list of fragments I can use for the "th:each" tag?

1

1 Answers

0
votes

This is not an especially elegant solution, but I think it does what you need. It re-arranges your approach, so it may need some translating to your specific context.

It is a bit brittle because you have to maintain a count of sections (explained below).

The layout.html:

<html xmlns:th="http://www.thymeleaf.org"
      th:fragment="layout">

    <section class="row-outer-sm"
             th:each="i,iterStat : ${#numbers.sequence(1, 3)}"
             th:with="section=${'section-' + i}">
        <div class="container">
            <div class="row justify-content-center">
                <div class="col">

                    <div th:if="${iterStat.first}">
                        Messages go here
                    </div>

                    <div th:replace="~{/content.html :: __${section}__} ">
                        Content goes here.
                    </div>
                </div>
            </div>
        </div>
    </section>

</html>

The content.html:

<html lang="en" xmlns:th="http://www.thymeleaf.org">

    <div th:fragment="section-1">
        <div class="section-content">
            Some things for my first section
        </div>
    </div>

    <div th:fragment="section-2">
        <div class="section-content">
            Some things for my second section
        </div>
    </div>

    <div th:fragment="section-3">
        <div class="section-content">
            Some things for my third section
        </div>
    </div>

</html>

The layout template builds a dynamically created fragment selector section_n, where n is the iterated value, based on Thymeleaf's sequence generator:

${#numbers.sequence(1, n)}

That is the brittle part - you have to remember to keep the hard-coded value of n in line with the number (and names!) of the section fragments in the content template.

We also use Thymeleaf's preprocesing __${}__ directive to allow the th:replace to operate on a string - the template selector.

In my example, the end result is HTML like this (the format's a bit wonky):

    <section class="row-outer-sm">
        <div class="container">
            <div class="row justify-content-center">
                <div class="col">

                    <div>
                        Messages go here
                    </div>

                    <div>
        <div class="section-content">
            Some things for my first section
        </div>
    </div>
                </div>
            </div>
        </div>
    </section>

    <section class="row-outer-sm">
        <div class="container">
            <div class="row justify-content-center">
                <div class="col">



                    <div>
        <div class="section-content">
            Some things for my second section
        </div>
    </div>
                </div>
            </div>
        </div>
    </section>

    <section class="row-outer-sm">
        <div class="container">
            <div class="row justify-content-center">
                <div class="col">



                    <div>
        <div class="section-content">
            Some things for my third section
        </div>
    </div>
                </div>
            </div>
        </div>
    </section>

Hope that helps, or at least gives you some inspiration.