Même si le moteur de template Thymeleaf est exécuté du côté serveur, il est possible de charger un fragment à la suite d'un évènement.
Dans notre page, nous avons une section avec l'id main
<div id="main" class="container-fluid">
</div>
Le fragment sera inséré à cet endroit après un appel sur le serveur.
var XHR = new XMLHttpRequest();
XHR.open('get', '/ajaxfragment');
XHR.send();
XHR.addEventListener('readystatechange', function() {
if (XHR.readyState === XMLHttpRequest.DONE && XHR.status === 200) {
document.getElementById("main").innerHTML = XHR.responseText;
}
});
Le code du contrôleur qui nous retourne notre fragment Thymeleaf.
@GetMapping(value = {"/ajaxfragment"})
public String getAjaxFragment(Model model) {
List<User> users = new ArrayList<>();
users.add(new User("Yvan", "Dubois"));
users.add(new User("Yvon", "Couler"));
users.add(new User("Ytord", "Lamope"));
model.addAttribute("users", users);
return "fragments/ajax::Ajax";
}
Le fragment Thymeleaf
<div th:fragment="Ajax">
<h3>Ajax fragment</h3>
<table class="table">
<tr th:each="user : ${users}">
<td th:text="${user.firstname}" />
<td th:text="${user.lastname}" />
</tr>
</table>
</div>
Cette stratégie peut être utilisé afin de rendre plus dynamique certaine partie de votre applicaiton web.
Les sources du projets: https://github.com/marccollin/thymeleaf
Blog sur la conception, développement et le génie logiciel. Divers langages et systèmes d'exploitations sont traités.
lundi 30 décembre 2019
dimanche 29 décembre 2019
Les formulaires avec thymeleaf
Dans un précédent tutoriel, le moteur de thymeleaf a été présenté rapidement. Nous allons ici présenté comment utiliser un formulaire avec ce moteur de template.
Nous verrons deux façon d'appréhender les formulaires.
La sauvegarde est complètement différentes.
Le formulaire est utilisé pour la sauvegarde d'un utilisateur.
Le modèle est
public class User {
private String firstname;
private String lastname;
private boolean enabled;
private String userTypeId;
...
}
public class UserType {
private Long id;
private String type;
...
}
Le code pour afficher le formulaire est
@GetMapping(value = {"/userform"})
public String getUserForm(Model model) {
List<UserType> userTypes = new ArrayList<>();
UserType userType1 = new UserType();
userType1.setId(1l);
userType1.setType("Admin");
UserType userType2 = new UserType();
userType2.setId(2l);
userType2.setType("Standard");
UserType userType3 = new UserType();
userType3.setId(3l);
userType3.setType("Invité");
userTypes.add(userType1);
userTypes.add(userType2);
userTypes.add(userType3);
model.addAttribute("user", new User());
model.addAttribute("userTypes", userTypes);
return "formuser";
}
La page html ne fait qu'ajouter quelques marqueurs
<!DOCTYPE html>
<html>
<head th:include="fragments/head :: HeadCss"/>
<body>
<div th:replace="fragments/top-menu :: TopMenu('user')"/>
<h3>Form User</h3>
<div id="main" class="container-fluid">
<form action="#" th:action="@{/userform}" th:object="${user}" method="post">
<div class="form-group row">
<label th:for="firstname" class="col-sm-2 col-form-label" >Prénom</label>
<div class="col-sm-10">
<input type="text" class="form-control" id="firstname" th:placeholder="#{user.firstname.placeholder}" th:field="*{firstname}" />
</div>
</div>
<div class="form-group row">
<label th:for="lastname" class="col-sm-2 col-form-label" >Nom</label>
<div class="col-sm-10">
<input type="text" class="form-control" id="lastname" th:placeholder="#{user.lastname.placeholder}" th:field="*{lastname}" />
</div>
</div>
<div class="form-group row">
<label th:for="userTypeId" class="col-sm-2 col-form-label" >Type</label>
<div class="col-sm-10">
<select id="type" th:field="*{userTypeId}">
<option th:each="userType : ${userTypes}" th:value="${userType.id}" th:text="${userType.type}"></option>
</select>
</div>
</div>
<div class="form-group row">
<label th:for="enabled" class="col-sm-2 col-form-label">Actif</label>
<div class="col-sm-10">
<input type="checkbox" th:field="*{enabled}" />
</div>
</div>
<div class="form-group">
<div class="col-sm-12">
<div class="float-right">
<button type="submit" class="btn btn-primary">Sauvegarder</button>
<button type="button" id="resetButton" class="btn btn-primary">Reset</button>
</div>
</div>
</div>
</form>
</div>
</body>
</html>
Dans le controller, deux variables sont assignés aux modèles via ces lignes
model.addAttribute("user", new User());
model.addAttribute("userTypes", userTypes);
Dans le formulaire,
th:action sert à spécifier l'url où sera soumis le formulaire
th:object sert à spécifier l'objet où sera lié les données soumises au formulaire
Les attributs de l'objet sont accessible th:field

La sauvegarde du système
@PostMapping(value = {"/userform"})
public String savUserForm(@ModelAttribute User user) {
System.out.println(user.toString());
//do want you want with value
return "savingok";
}
La deuxiême façon nécessite un peu de javascript, car le mapping devra être fait manuellement.
<form id="form">
<div class="form-group row">
<label for="firstname" class="col-sm-2 col-form-label" >Prénom</label>
<div class="col-sm-10">
<input type="text" class="form-control" id="firstname" th:placeholder="#{user.firstname.placeholder}" />
</div>
</div>
<div class="form-group row">
<label for="lastname" class="col-sm-2 col-form-label" >Nom</label>
<div class="col-sm-10">
<input type="text" class="form-control" id="lastname" th:placeholder="#{user.lastname.placeholder}" />
</div>
</div>
<div class="form-group">
<div class="col-sm-12">
<div class="float-right">
<button type="button" class="btn btn-primary" onclick="saveForm()" >Sauvegarder</button>
<button type="button" class="btn btn-primary">Reset</button>
</div>
</div>
</div>
</form>
Pour le javascript
<script type="text/javascript">
function toJSONString( form ) {
var obj = {};
var elements = form.querySelectorAll( "input, select, textarea" );
for( var i = 0; i < elements.length; ++i ) {
var element = elements[i];
var id = element.id;
var value = element.value;
if( id ) {
obj[ id ] = value;
}
}
return JSON.stringify( obj );
}
function saveForm() {
var XHR = new XMLHttpRequest();
XHR.open('POST', 'http://localhost:8080/userformrest');
XHR.setRequestHeader("Content-Type", "application/json;charset=UTF-8");
//JSON.stringify();
var formElement = document.querySelector("form");
var json = toJSONString(formElement);
var formData = new FormData(formElement);
XHR.send(json);
}
</script>
Le paramètre pour la sauvegarde est différent. Ce n'est plus l'annotation ModelAttribute qui est utilisé mais bien RequestBody.
@PostMapping(value = {"/userformrest"})
@ResponseBody
public ResponseEntity savUserFormRest(@RequestBody User user) {
System.out.println(user.toString());
//do want you want with value
return new ResponseEntity<>(HttpStatus.OK);
}
Le code est disponible à https://github.com/marccollin/thymeleaf.
Nous verrons deux façon d'appréhender les formulaires.
La sauvegarde est complètement différentes.
Le formulaire est utilisé pour la sauvegarde d'un utilisateur.
Le modèle est
public class User {
private String firstname;
private String lastname;
private boolean enabled;
private String userTypeId;
...
}
public class UserType {
private Long id;
private String type;
...
}
Le code pour afficher le formulaire est
@GetMapping(value = {"/userform"})
public String getUserForm(Model model) {
List<UserType> userTypes = new ArrayList<>();
UserType userType1 = new UserType();
userType1.setId(1l);
userType1.setType("Admin");
UserType userType2 = new UserType();
userType2.setId(2l);
userType2.setType("Standard");
UserType userType3 = new UserType();
userType3.setId(3l);
userType3.setType("Invité");
userTypes.add(userType1);
userTypes.add(userType2);
userTypes.add(userType3);
model.addAttribute("user", new User());
model.addAttribute("userTypes", userTypes);
return "formuser";
}
La page html ne fait qu'ajouter quelques marqueurs
<!DOCTYPE html>
<html>
<head th:include="fragments/head :: HeadCss"/>
<body>
<div th:replace="fragments/top-menu :: TopMenu('user')"/>
<h3>Form User</h3>
<div id="main" class="container-fluid">
<form action="#" th:action="@{/userform}" th:object="${user}" method="post">
<div class="form-group row">
<label th:for="firstname" class="col-sm-2 col-form-label" >Prénom</label>
<div class="col-sm-10">
<input type="text" class="form-control" id="firstname" th:placeholder="#{user.firstname.placeholder}" th:field="*{firstname}" />
</div>
</div>
<div class="form-group row">
<label th:for="lastname" class="col-sm-2 col-form-label" >Nom</label>
<div class="col-sm-10">
<input type="text" class="form-control" id="lastname" th:placeholder="#{user.lastname.placeholder}" th:field="*{lastname}" />
</div>
</div>
<div class="form-group row">
<label th:for="userTypeId" class="col-sm-2 col-form-label" >Type</label>
<div class="col-sm-10">
<select id="type" th:field="*{userTypeId}">
<option th:each="userType : ${userTypes}" th:value="${userType.id}" th:text="${userType.type}"></option>
</select>
</div>
</div>
<div class="form-group row">
<label th:for="enabled" class="col-sm-2 col-form-label">Actif</label>
<div class="col-sm-10">
<input type="checkbox" th:field="*{enabled}" />
</div>
</div>
<div class="form-group">
<div class="col-sm-12">
<div class="float-right">
<button type="submit" class="btn btn-primary">Sauvegarder</button>
<button type="button" id="resetButton" class="btn btn-primary">Reset</button>
</div>
</div>
</div>
</form>
</div>
</body>
</html>
Dans le controller, deux variables sont assignés aux modèles via ces lignes
model.addAttribute("user", new User());
model.addAttribute("userTypes", userTypes);
Dans le formulaire,
th:action sert à spécifier l'url où sera soumis le formulaire
th:object sert à spécifier l'objet où sera lié les données soumises au formulaire
Les attributs de l'objet sont accessible th:field
La sauvegarde du système
@PostMapping(value = {"/userform"})
public String savUserForm(@ModelAttribute User user) {
System.out.println(user.toString());
//do want you want with value
return "savingok";
}
La deuxiême façon nécessite un peu de javascript, car le mapping devra être fait manuellement.
<form id="form">
<div class="form-group row">
<label for="firstname" class="col-sm-2 col-form-label" >Prénom</label>
<div class="col-sm-10">
<input type="text" class="form-control" id="firstname" th:placeholder="#{user.firstname.placeholder}" />
</div>
</div>
<div class="form-group row">
<label for="lastname" class="col-sm-2 col-form-label" >Nom</label>
<div class="col-sm-10">
<input type="text" class="form-control" id="lastname" th:placeholder="#{user.lastname.placeholder}" />
</div>
</div>
<div class="form-group">
<div class="col-sm-12">
<div class="float-right">
<button type="button" class="btn btn-primary" onclick="saveForm()" >Sauvegarder</button>
<button type="button" class="btn btn-primary">Reset</button>
</div>
</div>
</div>
</form>
Pour le javascript
<script type="text/javascript">
function toJSONString( form ) {
var obj = {};
var elements = form.querySelectorAll( "input, select, textarea" );
for( var i = 0; i < elements.length; ++i ) {
var element = elements[i];
var id = element.id;
var value = element.value;
if( id ) {
obj[ id ] = value;
}
}
return JSON.stringify( obj );
}
function saveForm() {
var XHR = new XMLHttpRequest();
XHR.open('POST', 'http://localhost:8080/userformrest');
XHR.setRequestHeader("Content-Type", "application/json;charset=UTF-8");
//JSON.stringify();
var formElement = document.querySelector("form");
var json = toJSONString(formElement);
var formData = new FormData(formElement);
XHR.send(json);
}
</script>
Le paramètre pour la sauvegarde est différent. Ce n'est plus l'annotation ModelAttribute qui est utilisé mais bien RequestBody.
@PostMapping(value = {"/userformrest"})
@ResponseBody
public ResponseEntity savUserFormRest(@RequestBody User user) {
System.out.println(user.toString());
//do want you want with value
return new ResponseEntity<>(HttpStatus.OK);
}
Le code est disponible à https://github.com/marccollin/thymeleaf.
dimanche 1 décembre 2019
Débuter rapidement avec Thymeleaf
Débuter rapidement avec Thymeleaf
Thymeleaf est un moteur de template côté serveur. Tel que JSP, JSF, GWT, les pages sont généré sur le serveur. Ce moteur est entièrement supporté par Spring Boot.Ce moteur est majoritairement utilisé dans des applications, mais il peut être utilisé dans la construction de page pdf.
Thymeleaf utilise des pages html auquel des marqueurs (commande) sont ajouté pour aider le moteur à faire certain traitement.
Les exemples utilisés sont basé sur un projet en spring boot 2.2
public
class
User
{
private String firstname;
public User(){
public
String getFirstname() {
return
firstname
;
}
public
void
setFirstname(String
firstname) {
this
.
firstname =
firstname;
}
}
@Controller
public class UserController {
private final UserService userService;
public UserController(final UserService userService){
this.userService=userService;
}
@GetMapping(value="/userlist")
public String userList(Model model) {
List<User> usersList = userService.findAll();
model.addAttribute("users", usersList);
return "userList";
}
}
Le fichier html
<!DOCTYPE html>
<html>
<head>
<title>User list</title>
</head>
<body>
<table>
<tr th:each="user : ${users}">
<td th:text="#{firstname}"></td>
<td th:text="${user.firstname}"></td>
</tr>
</table>
</body>
</html>
th:each et th:text sont des marqueurs. Le premier permet de boucler sur la listes de users alors que le second permet d'afficher.
Au niveau du contrôleur, la variable usersList est mise dans le modèle avec le nom users.
Dans le fichier html, on y accède en bouclant sur la même variable avec la syntaxe ${nom de ma variable}.
L'usage #{...} permet d'avoir accès au fichier d'internalisation.
Dans le répertoire resources les fichiers- messages.properties
- messages_en.properties
Dans le fichier messages.properties
firstname=Prénom
et dans le fichier messages_en.properties
firstname=Firstname.
Condition
L'opérateur Elvis est disponible avec la même notation.Condition ? true : false
Si la valeur du firstname est Paul alors son fond de couleur sera blanc.
Afin que ça puisse fonctionner, il faut utiliser le marqueur th:style.
<!DOCTYPE html>
<html>
<head>
<title>User list</title>
</head>
<body>
<table>
<tr th:each="user : ${users}">
<td th:text="#{firstname}"></td>
<td th:text="${user.firstname}" th:style="${user.firstname=='Paul'} ? 'background: #ffffff' : ''"></td>
</tr>
</table>
</body>
</html>
Un projet basique est disponible.
Inscription à :
Articles (Atom)