Les templates en JavaScript avec la librairie Ext JS

Eric Pommereau

L'idée de vouloir séparer les données de la présentation n'est pas nouvelle, la quasi totalité des technos "côté serveur" implémentent un système de template. En revanche il n'est pas ordinaire de rencontrer ce mécanisme en JavaScript.
Je vous invite à découvrir cette fonctionnalité avec la librairie JavaScript Ext JS et son système de templates XTemplate.

- Titre : Les templates en JavaScript avec la librairie Ext JS

- Auteur : Eric Pommereau

- Parution : 12 octobre 2009

- Licence : Copyright ® 2009 Eric Pommereau. Aucune reproduction, même partielle, ne peut être faite de ce site et de l'ensemble de son contenu : textes, documents, images, etc. sans l'autorisation expresse de l'auteur. Sinon vous encourez selon la loi jusqu'à trois ans de prison et jusqu'à 300 000 € de dommages et intérêts.

Sommaire

- I. Introduction

- II. Les fonctionnalités en bref

- III. Données JSON de base

- IV. Utilisation de la classe XTemplate

- V. Tableau indexé parcours manuel

- VI. Tableau indexé parcours dynamique avec une boucle

- VII. Mise en forme conditionnelle

- VIII. Mise en forme conditionnelle alternative

- IX. Modificateurs de variables

- X. Variables spéciales XTemplate

- XI. Exemple de génération d'image HTML

- XII. Utilisation avec d'autres composants de la Ext JS

- XIII. Conclusion

I - Introduction

Le premier article que j'ai écris pour developpez.com (il y a un moment déjà) concernait alors le moteur de templates PHP smarty. Le principe d'un système de templates est de séparer le code de production des données du code responsable de la présentation. Si vous n'êtes pas familier ce qu'est un système de templates jetez y un coup d'oeil.

Depuis que j'utilise un système de templates en développement web, il m'est difficile de m'en passer. C'est également le cas en javacript tant, parfois, certaines parties de code deviennent difficilement lisibles et peu maintenables.

La librairie Ext JS implémente ce mécanisme sous la forme d'une classe, la classe XTemplates.
On peut comparer ce système de templates (en bien plus simple) au puissant langage XSLT qui permet des transformations de fichiers XML. Si l'on pousse la comparaison plus loin, le rôle de XSLT serait rempli par la classe XTemplate et à XML correspondrait les structures de données JavaScript (chaine, tableau ou objet).

J'aborderai la présentation de cette classe XTemplate par des exemples librement inspirés de la documentation officielle de la Ext JS (qui est très bien faire au demeurant).

II - Les fonctionnalités en bref

Voici les principales caractéristiques de la classe XTemplate :

D'abord, XTemplate permet de boucler sur un ensemble de données JavaScript, tableau indexé ou objet JSON y compris à plusieurs niveaux.

Ensuite l'affichage conditionnelle de données (seul le if est possible).

XTemplate offre également la possibilité de modifier (dans le template) une valeur en utilisant une méthode permise par son type (ex maString.toUpperCase()), c'est ce que j'appelle modificateur de variable par analogie avec la terminologie utilisée dans le moteur de templates PHP Smarty.

Certaines fonctionnalités internes au mécanisme de template permettent d'accéder :

- A l'index courant dans un boucle

- Au nombre d'éléments d'une boucle

- Aux valeurs dans la portée du template

- A l'élément parent d'une donnée

- A la fonction Ext.utils.format() qui permet l'accès à quelques outils de formatage de chaine de caractères

Enfin, il est possible, dans le template, d'effectuer certaines opérations arithmétiques (+, -, /, et *).

III - Données JSON de base

Voici les données de base que nous allons utiliser, ces données au format JSON qui seront utilisées tout au long de l'article, chaque exemple s'appuie sur ces données.

var jsonArray = {
service : 'sipj',
sections : ['réseau', 'etudes', 'développement', 'formation', 'cits', 'administratif'],
adresse : '122, rue du château des rentiers 75013 paris',
desc : 'Le service informatique fournit aux services de sa direction les moyens...',
bureau : 114,
collegues : [
{nom: 'arkel', age: 26},
{nom: 'jean', age: 27},
{nom : 'jean-luc', age : 45},
{nom : 'sylvain', age : 38},
]
}

IV - Utilisation de la classe XTemplate

Le concept de définir une chaine de caractères dans laquelle on insère des tags (ou étiquettes), dans un second temps le système de template substitue aux étiquettes les données que l'on aura choisi de transformer.

Ci-après une utilisation très basique de XTemplate :

var tpl = new Ext.XTemplate('Bonjour {.} !!');     // Création de l'objet tpl de type XTemplate, passage du template dans le constructeur
alert(tpl.apply('le monde'));    // Méthode qui retourne la transformation du template abec la donnée 'le monde'

Récapitulons : d'abord construction de l'objet de type XTemplate, le template qui est une chaine de caractères est passé comme argument du constructeur. Ensuite on utilise une méthode (dans l'exemple ci-dessus c'est la méthode apply()) pour lier à la transformation une action, dans notre cas il s'agit de retourner une chaine de caractères.

D'autres méthodes de l'objet XTemplate permettent différentes actions comme l'insertion ou le remplacement du résultat dans un élément HTML...

Voici les différentes méthodes de l'objet XTemplate :

Méthodes de la classe XTemplate

METHODE

ACTION

append( Mixed el, Object/Array values, [Boolean returnElement])

Applique les valeurs values au template et créé un noeud dans l'élément el

apply(Object/Array values) : string

Applique les valeurs values au template et retourne le résultat sous forme de chaine de caractères

insertAfter( Mixed el, Object/Array values, [Boolean returnElement] ) : HTMLElement/Ext.Element

Applique les valeurs values au template et insére le résultat dans un nouveau noeud après l'élément el

compile()

Compiler le template (pour améliorer les performances dans le cas d'appels répétés)

overwrite( Mixed el, Object/Array values, [Boolean returnElement] ) : HTMLElement/Ext.Element

Applique les valeurs values au template et écrase le contenu de l'élément el

V - Tableau indexé parcours manuel

Voici comment récupérer différentes valeurs d'un tableau indexé le tableau sections de l'objet JSON :

var tpl = new Ext.XTemplate('{0}, {1}, {2}');
tpl.overwrite('tpl_output', jsonData.sections);

Cet exemple ne présente pas grand intérêt en ce sens qu'il faut connaître le nombre d'éléments contenu dans le tableau indexé, néanmoins, c'est intéressant de connaître cette possibilité.

VI - Tableau indexé parcours dynamique avec une boucle

Même cas de figure que l'exemple précédent mais avec une technique différente est utilisée.

var tpl = new Ext.XTemplate('<tpl for=".">{.}, </tpl>');
tpl.overwrite('tpl_output', jsonData.sections);

Cet exemple permet de parcourir l'ensemble du tableau jsonData.sections.

L'instruction tpl for="{.}" indique au moteur de template de parcourir tous les éléments d'un tableau indexé.

On parle assez couramment de boucle pour désigner ce mécanisme puisque c'est le mécanisme sous-jacent.

VII - Mise en forme conditionnelle

Autre possibilité offert par la classe XTemplate, l'affichage conditionnel.

Dans l'exemple ci-après on modifie la propriété "background-color" selon que l'âge de la personne est supérieur ou inférieur à 30 ans.

var tpl = new Ext.XTemplate(
'<p>Service : {service}</p>',
'<p>Adresse : {adresse}, B {bureau}</p>',
'<tpl for="collegues">',
'<tpl if="age &gt; 30">',
'<p style="margin-left:10px;background-color:pink;">{nom}, {age} ans</p>',
'</tpl>',
'<tpl if="age &lt; 30">',
'<p style="margin-left:10px;background-color:teal;">{nom}, {age} ans</p>',
'</tpl>',
'</tpl>'
);

tpl.overwrite('tpl_output', jsonData);

Quelques remarques :

L'instruction tpl for="nodeName" permet d'itérer sur les objets de la collection nodeName.

L'instruction tpl if="value = 10" permet l'évaluation de la condition "value = 10" et, si l'évaluation est vraie, affiche le code contenu.

Pour les opérateur supérieur et inférieur, il faut impérativement utiliser les entités html correspondantes.

VIII - Mise en forme conditionnelle alternative

Rigoureusement le même exemple mais en utilisant une notation plus condensée :

var tpl = new Ext.XTemplate(
'<p>Service : {service}</p>',
'<p>Adresse : {adresse}, B {bureau}</p>',
'<tpl for="collegues">',
'<p style="margin-left:10px;background-color:{[values.age < 30 ? "teal" : "pink"]};">{nom}, {age} ans</p>',
'</tpl>'
);

tpl.overwrite('tpl_output', jsonData);

On gagne en concision mais on perd en lisibilité.

IX - Modificateurs de variables

A chaque variable accessible il est possible d'appliquer une méthode propre à sa classe. Par exemple les valeurs de type string acceptent la méthode .toUpperCase().

var tpl = new Ext.XTemplate(
'<p>Description : {[values.desc.toUpperCase()]}</p>'
);
tpl.overwrite('tpl_output', jsonData);

Il faut noter que l'on doit impérativement passer par la collection values qui est un conteneur pour les valeurs de la portée courante (là ou l'on se trouve dans la collection de données). A noter également l'obligation d'utiliser la notation {[...instruction...]} qui désactive le système de templates et provoque l'évaluation du code JavaScript qui se trouve à l'intérieur.

X - Variables spéciales XTemplate

Il est possible d'accéder à certaines variables internes. Ces variables permettent par exemple de connaître l'index de l'itération d'une boucle ou d'en connaître le nombre d'éléments

var tpl = new Ext.XTemplate(
'<tpl for="collegues">',
'<p style="margin-left:10px;">{[xindex + " / " + xcount]} {[fm.capitalize(values.nom)]}</p>',
'</tpl>'
);

tpl.overwrite('tpl_output', jsonData);

Quelques remarques s'imposent. Ces variables spéciales sont accessibles en utilisant le motif {[variable_speciale]} (entre accolade / crochet).
Cela nous permet, dans l'exemple, de récupérer l'index courant et le nombre d'éléments de la boucle.
Ensuite, l'instruction {[fm.capitalize(values.nom)]} nous a permis de mettre en capitales la variable nom sans pour autant appeler la méthode toUpperString() de la variable (elle même de type string). fm est en fait un "alias" de la classe Ext.util.format. Cette instruction nous permet un certain nombre de transformations de formatage de données très intéressantes et étendues comparé à ce dont on dispose en standard.

XI - Exemple de génération d'image HTML

L'utilisation des XTemplate se fait surtout dans le cadre des widget de la librairie Ext JS comme les grilles de données (Ext.grid.GridPanel). Au moment de la création des colonnes, il est possible de spécifier un "formater" (en fait une fonction personnalisée) dans laquelle il est intéressant d'implémenter un mécanisme de template.
Par expérience, l'affichage d'image en fonction de certaines conditions est un cas de figure qui revient assez souvent.

var baseUrl = 'http://localhost/';
var ressourceDir = 'resDir/';
var imageName = 'index.php?img=pngWrench';
var alt = 'Une image sans Xtemplate : exemple 1';

imageHtml = '<img src="' + baseUrl + ressourceDir + imageName + '" alt="' + alt + '" title="' + alt + '"/>');

Nous avons vu la manière "traditionnelle", voyons maintenant le même scénario en utilisant les templates :

var tpl = new Ext.XTemplate(
'<img src="{baseUrl}{ressourceDir}{imageName}" title="{alt}" alt="{alt}">'
);
tpl.overwrite(
'tpl_output', {
baseUrl: 'http://localhost/',
ressourceDir: '',
imageName:'index.php?img=pngWrench',
alt: 'Une image avec Xtemplate.'
}
);

Voilà, le résultat n'est pas spectaculaire mais c'est tout de même plus lisible.

Maintenant il faut imaginer ce mécanisme avec une collection au format JSON consommée par plusieurs templates voire commune à l'ensemble d'un projet.
On peut imaginer d'y mettre par exemple les différents chemins (application et ressources), le nom de certaines images ou encore des informations sur le paramétrage de l'application.

XII - Utilisation avec d'autres composants de la Ext JS

Un composant propose "nativement" l'utilisation de XTemplate, il s'agit du composant Ext.DataView.
Ce composant offre la possibilité d'afficher des données de type Ext.store affichées grâce aux règles définies dans un template (Ext.XTemplate).

Assez souvent il est courant d'utiliser XTemlate dans le renderer d'une colonne du composant Ext.grid.GridPanel. On utilise un renderer particulier lorsque l'on souhaite afficher une autre valeur que la valeur par défaut.
Par exemple modifier la couleur d'un élément selon qu'il est supérieur ou inférieur à une certaine valeur, ou pour afficher une image à la place d'une valeur (vu dans l'exemple ci-dessus).

Plus généralement, XTemplate peut s'utiliser partout où le besoin s'en fait sentir. Personnellement j'ai souvent recours aux templates lorsque je souhaite afficher des données au format JSON, c'est là, à mon sens, la forte valeur ajoutée de XTemplate.

XIII - Conclusion

J'ai volontairement omis de parler des fonctions au sein des templates, fonctionnalité qui me paraît "too much", mais sachez que ce mécanisme existe.

A noter le même mécanisme dans prototype.js, vérifier si c'est le cas dans d'autres librairies.

Remerciements