Search code examples
springhtmlthymeleaf

Duplicated thymeleaf fragment after each loop


I have a Thymeleaf template that should render the contents of a map. Here is the template:

<div class="akuiteo list-group" data-th-each="akuiteo:${akuiteoMap.akuiteoMap}">
    <div data-th-replace="akuiteo::akuiteoView(${akuiteo.value},${akuiteo.key})"></div>
</div>

In the akuiteoView I have:

<button data-th-fragment="akuiteoView(commits,akuiteoNr)" class="akuiteo-file" data-th-each="commit:${commits}" data-th-id="${akuiteoNr}">
    <p data-th-text="${akuiteoNr}"></p>
    <div data-th-replace="commitDetails::commitView(${commit})">replace me</div>
</button>

The output I get is:

<body>
    <div class="akuiteo list-group">
         <button> content </button>
    </div>
    <div class="akuiteo list-group">
         <button> content </button>
         <button> content </button>
         <button> content </button>
         <button> content </button>
         <button> content </button>
         <button> content </button>
    </div>
</body>

The div with the akuiteo class is duplicated, moreover there is one button for each commit instead of one button for each akuiteo instance, I can't understand why this happens, the expected output is:

<body>
    <div class="akuiteo list-group">
         <button> content(a list of one commit) </button>
         <button> content(a list of 6 commits) </button>
    </div>
</body>

Solution

  • This happens because of data-th-each. Thymeleaf iterates your map's entries and creates separate div for each entry. Then the same thing happens for buttons: thymeleaf render a new one for each commit. You should check out documentation explaining iterating using th:each.

    To obtain expected output (1 div and 2 buttons) you should redesign your pages, e.g. like that:

    <div class="akuiteo list-group">
        <button data-th-each="akuiteo:${akuiteoMap.akuiteoMap}">
            <span data-th-replace="akuiteo::akuiteoView(${akuiteo.value},${akuiteo.key})"></span>
        </button>
    </div>
    

    and:

    <span data-th-fragment="akuiteoView(commits,akuiteoNr)" data-th-each="commit:${commits}">
        <!-- here goes content of a single commit -->
    <span>
    

    By the way, a <button> tag shouldn't contain such elements like <div> or <p>. I don't know anything about commits' content but consider either redesigning <button> to <div> (to keep the commit structure containing <p> and <div>), or summarizing a commits from an akuiteo in textual form (to keep <button>).