Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

How do I "add to" a Thymeleaf fragment, rather than replace

I want to be able to take a thymeleaf fragment, use all the content inside it, but then, sometimes, add extra content from the page that consumes it. Typical case: I have a footer template which contains a script ref that I want on every page. On some pages I want to add another script ref, but not all.

I have the following setup (reduced complexity to focus on the point) in my web application:

layout.html:

<html>
    <body>
        <div class="container">
            <div fragment="content"></div>
        </div>
        <div th:replace="shared/footer :: footer"></div>
    </body>
</html>

shared/footer.html

<html>
    <body>
        <div th:fragment="footer" th:remove="tag">
            <script th:src="{@/scripts/a.js}"></script>
        </div>
    </body>
</html>

index.html

<html>
   <body>
       <div th:fragment="content" class="myClass">
           <h1>Oh hello</h1>
       </div>

       <!-- what do i put here?!!! -->
   </body>
</html>

What I would like to do is be able to add some extra content to footer, from the index.html:

e.g.:

<div th:addExtraStuff="footer">
    <script th:ref="@{scripts/b.js"></script>
</div>

so final result looks like this:

<html>
       <body>
           <div class="container">
               <div class="myClass">
                   <h1>Oh hello</h1>
               </div>
           </div>
           <div>
               <script src="/scripts/a.js"></script>
               <script src="/scripts/b.js"></script>
           </div>
       </body>
    </html>

Obviously th:addExtraStuff doesn't exist - but you get the idea. I want the existing content, and to be able to supply my own content. I think it will start to get too complicated if I put ALL possibilities in the fragment and then use evaluations to decide whether to actually include that possibility. I could be wrong though.

like image 294
peteisace Avatar asked Sep 15 '25 18:09

peteisace


2 Answers

One way I've solved this, without using a custom dialect, is to use arguments on the fragment I use as my layout template which I call 'main-layout'. This example allows you to leave out elements you don't need to override but any you provide will be added to whatever is in the 'main-layout' fragment.

The basic template looks like this

main-view.html

<!DOCTYPE html>
    <html lang="en" xmlns:th="http://www.thymeleaf.org" th:fragment="main-layout">
    <head>
        <title>Template Head Title</title>
        <th:block th:replace="${head} ?: ~{}" />
    </head>
    <body>
        <header>
            Common Template Header Here
            <th:block th:replace="${contentHeader} ?: ~{}" />
        </header>
        <main>
            Common Template Content Here
            <th:block th:replace="${content} ?: ~{}" />
        </main>
    </body>
    <footer>
        Common Template Footer Here
        <th:block th:replace="${footer} ?: ~{}" />
    </footer>
</html>

And using it looks like

<!DOCTYPE HTML>
<html th:replace="main-view.html :: main-layout (head=~{:: head}, contentHeader=~{:: header}, content=~{:: main}, footer=~{:: footer})">
    <head th:remove="tag">
        <title>Greeting Head</title>
    </head>
    <body>
        <header th:remove="tag">
            Greeting Content Header
        </header>
        <main th:remove="tag">
            Greeting Content
        </main>
    </body>
    <footer th:remove="tag">
        Greeting Footer
    </footer>
</html>
like image 148
DangerDan Avatar answered Sep 18 '25 10:09

DangerDan


I am not sure if I understand what you want to do, but how about this.
index.html:

<!DOCTYPE html>
<html xmlns:th="http://www.thymeleaf.org">
   <body>
   Hello World
   </body>

   <!-- Calling default scripts + custom scripts -->
   <div th:replace="fragments/script :: base_script(~{::script})">
      <script th:src="@{js/customjs1.min.js}"></script>
      <script th:src="@{js/customjs2.min.js}"></script>
      <script th:src="@{js/customjs3.min.js}"></script>
   </div>

   <!-- If you want to call only default scripts -->
   <!--<head th:replace="fragments/script :: base_script(null)"></head>-->
</html>

The default js files are called by default but you can add additional scripts.
templates/fragments/script.html:

<html xmlns:th="http://www.thymeleaf.org">
    <div th:fragment="base_script(scripts)">
        <!-- /* default js files */ -->
        <script th:src="@{js/defaul1.min.js}"></script>
        <script th:src="@{js/defaul2.min.js}"></script>
        <script th:src="@{js/defaul3.min.js}"></script>
        <th:block th:if="${scripts != null}">
            <th:block th:replace="${scripts}" />
        </th:block>
    </div>
</html>

Both of default js files and custom js files will be called in index.html.

<!DOCTYPE html>
<html>
   <body>
   Hello World
   </body>

   <!-- Calling default scripts + custom scripts -->
   <div>
      <!-- /* default js + custom js files */ -->
      <script src="/js/defaul1.min.js"></script>
      <script src="/js/defaul2.min.js"></script>
      <script src="/js/defaul3.min.js"></script>
      <script src="/js/customjs1.min.js"></script>
      <script src="/js/customjs2.min.js"></script>
      <script src="/js/customjs3.min.js"></script>
   </div>

</html>
like image 37
lechat Avatar answered Sep 18 '25 08:09

lechat