devstory

Utiliser Fragments dans Thymeleaf

  1. Qu'est-ce que Fragment ?
  2. th:insert, th:replace, th:include
  3. Fragment với các tham số
  4. th:assert

1. Qu'est-ce que Fragment ?

Un Fragment fait partie d'un Template. Thymeleaf vous permet d'importer des fragments de ce Template dans un autre Template. Il existe de nombreuses façons d'identifier un Fragment. Par exemple :
  • Sélectionnez toutes les étiquettes (tag) avec l'attribut (attribute) th:fragment="search-fragment".
  • Séléctionnez l'étiquette par ID.
  • Sélectionnez toutes les étiquettes par Css-class.
  • ....
L'important, lorsque vous voulez importer un Fragment d'un Template, c'est que vous devez décrire sa position.
La syntaxe pour décrire la position d'un Fragment d'un Template :
~{/path-to-template/template-name :: selector}
Si vous voulez décrire la position de Fragment d'un Template courant il est possible d'utiliser une syntaxe plus concise :
~{:: selector}

~{this :: selector}
~{templatename: fragmentname} (th:fragment)
Sélectionnez un fragment par nom.
~{templatename: tagname} (Tag Name)
Choisissez un fragment par le nom de l'étiquette.
Sélectionnez les sous-balises d'une étiquette. Par exemple, sélectionnez toutes les étiquettes <script> situées dans les balises <header> :
~{templatename: #id} (ID)
Sélectionnez le fragment par la valeur de l'attribut (attribute) ID de l'étiquette.
~{templatename: .classname},~{templatename: tagname.classname} (Css Class)
Sélectionnez fragment par Css Class :
~{templatename} (Everything)
Sélectionnez toutes dans Template :
Other...
Autres exemples :
~{fragments/my-template :: #tagId/text() }

~{fragments/my-template :: fragmentName/text() }

~{fragments/my-template :: tagName/text() }

2. th:insert, th:replace, th:include

La fonction qui permet d'importer des fragment d'un Template à un autre Template est vraiment géniale. Il permet de faciliter la conception de l'interface du site web. Prenons l'exemple suivant :
Dans cet exemple, le fichier my-template.html contient plusieurs fragment, que autres Template peuvent importer pour utiliser.
/fragments/my-template.html
<!DOCTYPE HTML>
<html xmlns:th="http://www.thymeleaf.org">
<head>
    <meta charset="UTF-8" />
    <title>My Template</title>
    <link rel="stylesheet" type="text/css" th:href="@{/main.css}"/>
    <link rel="stylesheet" type="text/css" th:href="@{/secondary.css}"/>
    <script type="text/javascript" th:src="@{/main.js}"></script>
    <script type="text/javascript" th:src="@{/secondary.js}"></script>
</head>
<body>
    <!-- Script in body -->
    <script type="text/javascript" th:src="@{/script-in-body.js}"></script>
    <ul th:fragment="my-fragment1">
        <li><a th:href="@{/}">Home</a></li>
        <li><a th:href="@{/products}">Products</a></li>
        <li><a th:href="@{/about}">About</a></li>
    </ul>
    <ul th:fragment="my-fragment2">
        <li><a th:href="@{/admin/products}">Product Management</a></li>
        <li><a th:href="@{/admin/orders}">Order Management</a></li>
    </ul>
    <div id = "my-id1">
         Element DIV with id = 'my-id1'
    </div>
    <aside>
        <div>This is a sidebar</div>
    </aside>
    <p class="my-class">Element P with class (my-class)</p>
    <p>Element P without class</p>
    <p class="my-class">Element P with class (my-class)</p>
</body>
</html>
Le fichier my-page.html est un Template, il importe quelques fragment du my-template.html:
my-page.html (Template)
<!DOCTYPE HTML>
<html xmlns:th="http://www.thymeleaf.org">
<head>
<meta charset="UTF-8" />
<title th:replace = "~{fragments/my-template :: title}">Title</title>
<th:block th:insert="~{fragments/my-template :: link}"></th:block>
<th:block th:insert="~{fragments/my-template :: head/script}"></th:block>
</head>
<body>
   <h1>My Page</h1>
   <p>Some Content of My Page</p>
   <div th:insert="~{fragments/my-template :: my-fragment1}"></div>
   <div th:insert="~{fragments/my-template :: my-fragment2}"></div>
   <div th:insert="~{fragments/my-template :: #my-id1}"></div>
   <div th:insert="~{fragments/my-template :: p.my-class }"></div>
</body>
</html>
Le résultat que vous recevez :
(HTML Result)
<!DOCTYPE HTML>
<html>
<head>
    <meta charset="UTF-8" />
    <title>My Template</title>
    <link rel="stylesheet" type="text/css" href="/main.css" />
    <link rel="stylesheet" type="text/css" href="/secondary.css" />
    <script type="text/javascript" src="/main.js"></script>
    <script type="text/javascript" src="/secondary.js"></script>
</head>
<body>
    <h1>My Page</h1>
    <p>Some Content of My Page</p>
    <div>
        <ul>
            <li><a href="/">Home</a></li>
            <li><a href="/products">Products</a></li>
            <li><a href="/about">About</a></li>
        </ul>
    </div>
    <div>
        <ul>
            <li><a href="/admin/products">Product Management</a></li>
            <li><a href="/admin/orders">Order Management</a></li>
        </ul>
    </div>
    <div>
        <div id="my-id1">
            Element DIV with id = 'my-id1'
        </div>
    </div>
    <div>
        <p class="my-class">Element P with class (my-class)</p>
        <p class="my-class">Element P with class (my-class)</p>
    </div>
</body>
</html>
th:insert, th:replace, th:include
  • th:insert va insérer Fragment pour agir comme l'enfant de l'étiquette (Target tag).
  • th:replace remplacera l'étiquette cible par Fragment.
  • th:include va insérer l'enfant de Fragment pour agir comme l'enfant de l'étiquette cible.
Remarque : L'attribut (attribute) th:include est utilisé dans Thymeleaf 2, et il ne sera pas utilisé dans le version Thymeleaf 3.
/path/mytemplate.html (Fragments)
<footer th:fragment="copyright">
  &copy; o7planning.org
</footer>
Target Template:
(Target Template)
<body>
  ...
  <!-- th:insert -->
  <div th:insert="~{/path/mytemplate :: copyright}"></div>
  <!-- th:replace -->
  <div th:replace="~{/path/mytemplate :: copyright}"></div>
  <!-- th:include -->
  <div th:include ="~{/path/mytemplate :: copyright}"></div>
</body>
Résultat :
(HTML Result)
<body>
  ...
  <!-- th:insert -->
  <div>
    <footer>
      &copy; o7planning.org
    </footer>
  </div>
  <!-- th:replace -->
  <footer>
    &copy; o7planning.org
  </footer>
  <!-- th:include -->
  <div>
    &copy; o7planning.org
  </div>
</body>

3. Fragment với các tham số

Un fragment sera comme une fonction (function) s'il ajoute des paramètres et heureusement le Thymeleaf soutient pour le faire.
Paramètres explicites :
Si vous déclarez un fragment et énumérez explicitement sa liste de paramètres. Ces paramètres seront des paramètres obligatoires comme dans l'exemple suivant :
<div th:fragment="person (firstName, lastName)" class="box">
    <p>First Name: <span th:utext="${firstName}"></span></p>
    <p>Last Name: <span th:utext="${lastName}"></span></p>
    <p>Full Name: <span th:utext="${firstName} + ' '+ ${lastName}"></span></p>
</div>
Ajoutez des paramètres lorsque vous appelez fragment :
<div th:replace="~{fragments/my-template2 :: person('Donald', 'Trump') }"></div>
    
<div th:replace="~{fragments/my-template2 :: person( firstName='Donald', lastName= 'Trump') }"></div>

<div th:replace="~{fragments/my-template2 :: person( ${u.firstName}, ${u.lastName}) }"></div>

<div th:replace="~{fragments/my-template2 :: person( firstName=${u.firstName}, lastName= ${u.lastName}) }"></div>
Paramètres implicites
Vous pouvez créer un fragment avec des paramètres implicites. Il s'agit de paramètres facultatifs, comme dans l'exemple suivant :
<!-- Fragment with implicit parameters. -->
<div th:fragment="greeting" class="box">
    <p>Hello
       <span th:utext="${title}"></span>
       <span th:utext="${name} ?: 'There'"></span>
    </p>
</div>
Appelez fragment qui contient des paramètres implicites.
<div th:replace="~{fragments/my-template2 :: greeting(title='Mr.', name = 'Tom') }"></div>    
    
<div th:replace="~{fragments/my-template2 :: greeting }"></div>

4. th:assert

L'attribut (attribute) th:assert vous aide à évaluer une expression, ou plusieurs expressions (Expressions séparées par des virgules). Si toutes les expressions sont évaluées comme étant true (vraie), il n'y aura aucun problème, si une expression est évaluée comme false (fausse), une exception sera levée.
<div th:fragment="employee (firstName, lastName)" class="box"
     th:assert= "${!#strings.isEmpty(firstName)}, ${!#strings.isEmpty(lastName)}">
    
    <p>First Name: <span th:utext="${firstName}"></span></p>
    <p>Last Name: <span th:utext="${lastName}"></span></p>
    <p>Full Name: <span th:utext="${firstName} + ' '+ ${lastName}"></span></p>
</div>