Templates
1. Définition
JSF dispose d'une fonctionnalité appelée Templating qui permet de créer une page XHTML servant comme base ou modèle aux autres pages; cette page XHTML appelée template (gabarit) permet d'avoir des pages ayant la même structure. Le Templating facilite le maintien d'un aspect standard pour un grand nombre de pages au sein d'une application web développée avec JSF.
Pour réaliser une page template on utilise un ensemble de tags issus du namespace http://xmlns.jcp.org/jsf/facelets; ces tags sont préfixés par "ui" comme on le présentera dans la suite de cet article.
2. Les tags de Facelets spécifiques pour les templates
Tags | Fonctions |
ui:component |
ce tag permet de définir un composant créé et ajouté à l'arbre des composants. |
ui:composition | Définit une composition de page (attribut template optionnel); ce qui est à l’extérieur de ce tag est ignoré |
ui:debug | Définit un composant de debug qui est est créé et ajouté à l'arbre des composants. |
ui:decorate | Similaire au tag composition mais n'ignore pas le contenu en dehors de ce tag. |
ui:define | Définit un contenu qui est inséré dans une page par une template |
ui:fragment | Similaire au tag component mais n'ignore pas le contenu en dehors de ce tag |
ui:include | Encapsule une autre page. |
ui:insert | Insérer un contenu dans un template. Ce qu’il y a à l’intérieur de ce tag est le contenu par défaut |
ui:param | Utilisé pour passer un paramètre dans un fichier passé par un "include". |
ui:repeat | utilisé comme une alternative pour les tags permettant de faire des boucles comme c:forEach ou h:dataTable. |
ui:remove | Enlever un contenu d'une page |
.....
On se sert de ces tags et d'autres tags "HTML" pour construire la page template (modèle ou Gabarit) qui permettra d'avoir une structure homogène de toutes les pages du projet où sera utilisé la template. Comme page XHTML elle contient les espaces de noms relatives à XHTML, et comme Facelet on lui rajoute d'autres espaces de noms comme "xmlns:ui="http://xmlns.jcp.org/jsf/facelets"" et " xmlns:h="http://xmlns.jcp.org/jsf/html" ". Au sein de la template on s’intéressera spécialement aux tags "<ui:insert name ="nomDutag">" et "</ui:insert>" qui délimitent les parties de la template qui seront remplacées par du contenu qui proviendra des templates clientes.
les différentes pages de l'application qui utiliseront la page "template.xhtml" s'appellent des templates clientes; c'est au sein de ces celle-ci que seront définies les contenues des différents tags " <ui:insert ...". Dans la template cliente on aura par exemple des tags "<ui:define name="nomDutag">" et "</ui:define>" qui délimiteront ce qui sera inserré entre les tags "<ui:insert name ="nomDutag">" et "</ui:insert>".
.....
Exemple de template "template.xhtml"
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd"> <html xmlns="http://www.w3.org/1999/xhtml" xmlns:ui="http://xmlns.jcp.org/jsf/facelets" xmlns:h="http://xmlns.jcp.org/jsf/html"> <h:head> <meta http-equiv="Content-Type" content="text/html; charset=UTF-8" /> <h:outputStylesheet name="./css/default.css"/> <h:outputStylesheet name="./css/cssLayout.css"/> <title>#{pageTitle}</title> </h:head> <ui:param name="copyright" value="© Aly Omara 2015"/> <h:body> <div id="top"> <ui:insert name="top">Top</ui:insert> </div> <div> <div id="left"> <ui:insert name="left">Left</ui:insert> </div> <div id="content" class="left_content"> <h1>#{pageTitle}</h1> <ui:insert name="content">Content</ui:insert> </div> </div> <div id="bottom"> <ui:insert name="bottom">Template - #{copyright}</ui:insert> </div> </h:body> </html>
Explications et détails:
( à suivre)...
Exemple de template cliente
<ui:composition xmlns:ui="http://xmlns.jcp.org/jsf/facelets" template="./template.xhtml" xmlns:h="http://xmlns.jcp.org/jsf/html" xmlns="http://www.w3.org/1999/xhtml"> <ui:param name="pageTitle" value="Edit Person : #{bean.person.displayName}"/> <ui:define name="top"> Top of the page </ui:define> <ui:define name="content"> <h:form> <h:panelGrid columns="2"> <h:outputLabel value="First Name" class="label"/> <h:inputText value="#{bean.person.firstName}"/> <h:outputLabel value="Last Name" class="label"/> <h:inputText value="#{bean.person.lastName}"/> <h:outputLabel value="Customer Notes" class="label"/> <h:inputTextarea value="#{bean.person.notes}"/> </h:panelGrid> </h:form> </ui:define> <ui:define name="bottom"> Template Client Defined #{copyright} </ui:define> </ui:composition>
3. Composants UI
Dans JSF on a deux grands types de composants UI; le premier type est l'ensemble de composants qui permettent d' initier une action comme cliquer sur un bouton par exemple, et le deuxième type est l'ensemble de composants UI qui fournissent des données comme "input" par exemple. Le comportement des différents composants JSF sont décrits et implémentés soit par l'interface UICommand pour le premier type et par l'un des deux interfaces ValueHilder ou EditableValueHolder pour le second type. L'interface EditableValueHolder permet aux composants d'avoir leurs valeurs modifiables par les utilisateurs. La raison d'être de ces interfaces est de fournir la plus haute abstraction possible permettant d'encapsuler les capacités des composants UIs (interface utilisateur) de JSF.
( à suivre)
4. Composants Composés
4.1. Définition
La technologie JavaServer Faces propose le concept de composants composés avec les Facelets et c'est ce qui permet à chacun de créer sa propre bibliothèques de tags; un composant composé est un nouveau composant créé à partir d'autres composants. Pour créer un composant composé, il faut créer un Facelet (fichier ".xhtml") qui contient la définition du composant composé; celle-ci est formée de deux parties :
- Interface: c'est la partie qui décrit les attributs des balises associées au composant,
- Implémentation, la partie du composant qui contient la définition des différents tags du composant composé à créer.
Chaque composant peut avoir des validators, des convertors et des listeners qui lui sont attachés pour améliorer ses performances. Avec les Facelets toute page XHTML avec ses balises, ses tags JSF et ses composants peut être incluse dans une autre page ou utilisée comme élément d'un autre composant. On peut ainsi former des bibliothèques de composants pour des utilisations appropriées; toutefois avant de commencer à créer ses propres composants il faut vérifier s'il n'en existe pas déjà dans les différents tagLib associés à JSF.
4.2. Balises des Composants Composés
composite: interface
Cette balise déclare qu'on va utiliser un composant pour un composant composé. Le composant composé peut être utilisé comme simple composant.
composite: implementation
Cette balise définit l'implémentation du composant précisé dans la balise <composite:interface ...>.
composite:attribute
Cette balise déclare un attribut qui sera donné à une instance du composant composé au sein duquel il est présent. Pour de plus amples informations il faut voir la liste complète des tags dans la documentation des facelets.
composite: insertChildren
cette Balise est utilisée dans un marqueur <composite:implementation>. Tous les composants fils ou les templates seront insérés dans la représentation de ce composant.
composite: valueHolder
cette Balise précise que le composant composé qui lui est associé est déclaré par le marqueur "composite:interface" .... (à compléter)
composite: editableValueHolder
... (à faire)
composite: actionSource
...(à faire).
4.3. Interface et implémentation
Les tags 'composite: interface', 'composite: attribute' et 'composite: implementation' de 'composite' servent à définir le contenu de chaque 'composant composé'.
Interface
Le tag composite: interface est utilisé pour déclarer les valeurs configurables qui sont exposées au développeur qui l'utilisent.
Implémentation
Le tag 'composite:implementation' déclare toutes les balises XHTML qui seront contenues dans le composant composé.
Exemples d'utilisation
Considérons les lignes de codes suivantes qui seraient appelées à apparaître dans plusieurs page (Facelets) pour un formulaire qui permet de se connecter sur une page au sein d'une application:
<h:form>
<h:panelGrid columns="3"> <h:outputText value="Name:" /> <h:inputText value="#{user.name}" id="name"/> <h:message for="name" style="color: red" /> <h:outputText value="Password:" /> <h:inputText value="#{user.password}" id="password"/> <h:message for="password" style="color: red" /> </h:panelGrid> <h:commandButton actionListener="#{userService.register}" id="loginButton" action="status" value="submit"/> </h:form>
Pour éviter de réécrire ces lignes on peut définir un composant composé comme suit:
1. on crée un fichier XHTML qu'on va appeler ici "login.xhtml" par exemple, on y inscrit le code ci-dessus et on sauvegarde ce fichier dans le répertoire "ressources/repertoire_des-composant_composite" (le répertoire est un répertoire classique de toute application JSF)
2. on crée un espace de nom (appelons ce espace de nom "mon_composite") et on l'ajoute aux différents espaces de nom de l'application
3. On complète la définition de notre composant composite en précisant les parties "interface" et "implementation" ce qui donne comme fichier "login.xhtml":
Exemple de fichier composant composé
<?xml version='1.0' encoding='UTF-8' ?> <!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd"> <html xmlns="http://www.w3.org/1999/xhtml" xmlns:cc="http://xmlns.jcp.org/jsf/composite" xmlns:h="http://xmlns.jcp.org/jsf/html"> <!-- INTERFACE --> <cc:interface> <cc:attribute name="name"/> <cc:attribute name="password"/> <cc:attribute name="actionListener" method-signature= "void action(javax.faces.event.Event)" targets="ccForm:loginButton"/> </cc:interface> <!-- IMPLEMENTATION --> <cc:implementation> <h:form id="ccForm"> <h:panelGrid columns="3"> <h:outputText value="Name:" /> <h:inputText value="#{cc.attrs.name}" id="name"/> <h:message for="name" style="color: red" /> <h:outputText value="Password:" /> <h:inputText value="#{cc.attrs.password}" id="password"/> <h:message for="password" style="color: red" /> </h:panelGrid> <h:commandButton id="loginButton" action="status" value="submit"/> </h:form> </cc:implementation> </html>
....
Dans ce fichier "login.xhtml" on a défini le composant composé qu'on va utiliser dans d'autre fichier (Facelet) qui nécessite un formulaire login. Mais comment faire?
L'espace de nom du composant composite sera une association de "http://xmlns.jcp.org/jsf/composite" et "repertoire_des-composant_composite". Le nom du nouveau tag ainsi créé est le nom du fichier contenant la définition du composant composé sans l'extension ".xhtml" . si on définit l'espace de nom comme suit:
"xmlns:mc="http://xmlns.jcp.org/jsf/composite/repertoire_des-composant_composite"
Alors dans les facelets utilisant le composant composé on aura le tag <mc:login ....> comme présenté ci-dessous:
<html xmlns="http://www.w3.org/1999/xhtml" xmlns:mc="http://xmlns.jcp.org/jsf/composite/mycomp" <!-- . . . --> <mc:login/> </html>
...