Mustache.js et ICanHaz.js au secours de jQuery

Ludovic Chane Won In

Qui n'a jamais entendu de la bouche d'un développeur backend (pour ne pas dire Java) « JavaScript, moins j'en fais, mieux je me porte ». Je parle en connaissance de cause car j'étais assez imperméable à JavaScript par le passé. Mais je ne faisais que « bidouiller » du JavaScript car en vérité, je ne connaissais pas le langage et après quelques lectures d'ouvrages de référence (Javascript : Gardez le meilleur ! de Douglas Crockford par exemple), je me suis surpris à apprécier JavaScript de plus en plus. Et du JavaScript, il y en a partout, déguisé derrière du jQuery, et même côté serveur avec Node.js. Dans cet article, je vais vous parler d'une librairie JavaScript très spécifique, qui ne fait qu'une seule chose mais qui le fait bien. Il s'agit de la librairie de templating Mustache.js.

Cet article a été publié avec l'aimable autorisation de Ippon technologies.

Commentez

- Titre : Mustache.js et ICanHaz.js au secours de jQuery

- Auteur : Ludovic Chane Won In

- Parution : 21 juin 2013

- Licence : Les sources présentées sur cette page sont libres de droits et vous pouvez les utiliser à votre convenance. Par contre, la page de présentation constitue une œuvre intellectuelle protégée par les droits d'auteur. Copyright ® 2013 Ludovic Chane Won In. 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. jQuery sans les moustaches

- II. Les balises Mustache

- II-A. {{#name}}, la moustache de section

- II-B. {{^name}}, la moustache inverse

- II-C. {{! comment}}, la moustache invisible

- II-D. {{> tag}}, la moustache partielle

- III. Fonctions

- IV. Template multi lignes

- V. ICanHaz.js

- VI. Conclusion et remerciements

- VI-A. Remerciements

I - jQuery sans les moustaches

Imaginons que l'on veuille afficher une liste de livres (titre, auteur) que l'on récupère sous forme d'objet JavaScript. Voici le code JavaScript / jQuery correspondant :

var book = { title: "Javascript: the Good Parts", author: "Douglas Crockford" };
$('#example').append('Title: <b>' + book.title + '</b><br/>Author: ' + book.author);

Et le résultat :

Le contenu dynamique ne peut pas être affiché dans ce support, veuillez consulter la page en ligne.

Je ne sais pas vous, mais cette ligne-là m'irrite un peu quand je la lis et encore plus quand je l'écris :

$('#example').append('Title: <b>' + book.title + '</b><br/>Author: ' + book.author);

Pleins de ' et de +, c'est facile de s'y perdre et surtout, on mélange affichage et données. En Java, il existe de nombreux systèmes de templates pour mettre en œuvre cette séparation : Velocity, Freemarker, StringTemplate et j'en passe. Et bien en JavaScript, il existe également des systèmes de template dont Mustache, que je trouve simple et pourtant très puissant. Alors faisons appel à Mustache.js et voyons comment on peut rendre l'exemple précédent plus sexy.

var data = {title: "Javascript: the Good Parts", author: "Douglas Crockford"};
var template = 'Title: <b>{{title}}</b> <br/> Author: {{author}}';
var output = Mustache.render(template, data);
$('#example').append(output);

Le contenu dynamique ne peut pas être affiché dans ce support, veuillez consulter la page en ligne.

Ah finis les ' et + parasites ! On a maintenant une belle séparation entre le template et les données. On utilise Mustache.render qui prend en paramètre le template et notre objet de données data. Dans le template, il y a deux balises {{title}} et {{author}} qui vont être remplacées par les valeurs correspondantes de l'objet data lors de l'appel à Mustache.render.

On peut donc faire une première observation, un template Mustache est composé de balises et une balise est délimitée par des doubles accolades : les fameuses moustaches !

II - Les balises Mustache

Pour l'instant, nous n'avons vu qu'un type de balise ({{name}}) qui permet d'afficher la valeur de l'attribut name de votre objet de données. Dans le jargon Mustache, name est la clé de la balise. Voici un petit listing des balises Mustache qui existent.

II-A - {{#name}}, la moustache de section

Cette balise va ouvrir ce que Mustache appelle une section. Cette section peut contenir du text/html ou des balises Mustache. Une section est fermée par une balise {{/name}}. Si l'attribut name existe dans votre objet de données et est non vide et ne vaut ni null ni undefined, alors Mustache va interpréter cette section. Dans le cas contraire, la section n'est pas interprétée.

var data = {title: "Javascript: the Good Parts", author: ""};
var template = '{{#title}} Title: <b>{{title}}</b> {{/title}} {{#author}} ne sera pas affiché {{/author}}';
var output = Mustache.render(template, data);
$('#example').append(output);

Le contenu dynamique ne peut pas être affiché dans ce support, veuillez consulter la page en ligne.

Si name est un tableau, alors Mustache va itérer sur ce tableau et interpréter la section autant de fois que nécessaire.

var data = { books: [ "Javascript: the Good Parts", "Clean Code" ] };
var template = '{{#books}}<li>{{.}}</li>{{/books}}';
var output = Mustache.render(template, data);
$('#example').append(output);

Le contenu dynamique ne peut pas être affiché dans ce support, veuillez consulter la page en ligne.

Notez l'utilisation de {{.}} afin d'afficher l'élément du tableau.

II-B - {{^name}}, la moustache inverse

C'est l'inverse de la balise {{#name}}, c'est-à-dire que le corps de la balise ne sera interprété que si l'attribut name n'existe pas, est vide, vaut null ou undefined dans votre objet de données. Exemple :

var data = { books: [ ] };
var template = '{{#books}}<li>{{.}}</li>{{/books}} {{^books}}Aucun livre{{/books}}';
var output = Mustache.render(template, data);
$('#example').append(output);

Le contenu dynamique ne peut pas être affiché dans ce support, veuillez consulter la page en ligne.

II-C - {{! comment}}, la moustache invisible

C'est la balise de commentaire. Tout ce qu'il y a entre les moustaches est ignoré.

var data = {title: "Javascript: the Good Parts", author: "Douglas Crockford"};
var template = 'Le commentaire suivant ne sera pas affiché : {{! ne doit pas être affiché}}';
var output = Mustache.render(template, data);
$('#example').append(output);

Le contenu dynamique ne peut pas être affiché dans ce support, veuillez consulter la page en ligne.

II-D - {{> tag}}, la moustache partielle

Avec Mustache, il est possible de définir des templates partiels afin de décomposer ceux qui seraient trop verbeux ou que vous récupérez de plusieurs sources.

var data = {title: "Javascript: the Good Parts", author: "Douglas Crockford"};
var template = 'Title: <b>{{title}}</b> <br/>{{> tplAuthor}}';
var partials = { tplAuthor: 'Author: {{author}}' };
var output = Mustache.render(template, data, partials);
$('#example').append(output);

Le contenu dynamique ne peut pas être affiché dans ce support, veuillez consulter la page en ligne.

III - Fonctions

Dans votre objet de données, vous n'êtes pas cantonné à avoir uniquement des valeurs ou des tableaux. Vous pouvez également définir des fonctions qui vont déterminer le texte à afficher. Exemple :

var i = 0;
var data = { currentdate: function() { return i++;} };
var template = '<li>{{currentdate}}</li>';
$('#example').append(Mustache.render(template, data));
$('#example').append(Mustache.render(template, data));
$('#example').append(Mustache.render(template, data));

Le contenu dynamique ne peut pas être affiché dans ce support, veuillez consulter la page en ligne.

Oui j'avoue, ça c'était l'exemple facile avec les fonctions. On peut faire un poil plus évolué. Dans les exemples précédents avec les livres, on affiche le titre en gras. Imaginons que l'on veuille rendre paramétrable l'affichage de title, donc au choix en gras, en italique ou ce que vous voulez. Il suffit de fournir une fonction qui va faire ça.

var data = {
title: "Javascript: the Good Parts",
titleDisplay: function() {
return function(text, render) {
return '<b>' + render(text) + '</b>';
}
}
};
var template = 'Title: {{#titleDisplay}} {{title}} {{/titleDisplay}}';
var output = Mustache.render(template, data);
$('#example').append(output);

Le contenu dynamique ne peut pas être affiché dans ce support, veuillez consulter la page en ligne.

Mais maintenant, si je veux afficher le titre en italique et l'entourer par des guillemets, on remplace le corps de la fonction par :

return '"<i>' + render(text) + '</i>"';

Le contenu dynamique ne peut pas être affiché dans ce support, veuillez consulter la page en ligne.

Donc celui qui fournit l'objet data peut maintenant personnaliser l'affichage du titre.

IV - Template multi lignes

« T'es bien gentil Ludo, mais tes exemples sont simplistes, tes templates ne tiennent que sur une seule ligne. Tiens prend ce template-là. C'est beaucoup moins beau du coup et on peut vite oublier un antislash… »

var template = 'Title: {{title}} <br/>\
Author: {{author}} <br/>\
Edition: {{edition}}';

Effectivement, ce n'est pas très sexy. Alors il y a une petite astuce. Il suffit de mettre le template dans une balise <script> de type text/html, de récupérer son contenu et de le passer à Mustache ! En exemple, ça donne :

<script id="book" type="text/html">
Title: {{title}} <br/>
Author: {{author}} <br/>
Edition: {{edition}}
</script>

var data = {title: "Javascript: the Good Parts", author: "Douglas Crockford", edition: "O'Reilly"};
var template = $('#book').html();
var output = Mustache.render(template, data);
$('#example').append(output);

Le contenu dynamique ne peut pas être affiché dans ce support, veuillez consulter la page en ligne.

Mais on peut faire encore mieux !

V - ICanHaz.js

ICanHaz.js est une petite librairie JavaScript qui englobe Mustache.js et qui reprend l'idée de définir ses templates dans des balises script de type text/html. Au chargement de la page, ICanHaz.js va rechercher tous les templates de la page, créer un cache les contenant et une fonction pour chacun d'eux. À l'utilisation, c'est encore plus simple que Mustache.js. Si on reprend l'exemple précédent, le JavaScript devient :

<script id="book" type="text/html">
Title: {{title}} <br/>
Author: {{author}} <br/>
Edition: {{edition}}
</script>

var data = {title: "Javascript: the Good Parts", author: "Douglas Crockford", edition: "O'Reilly"};
var output = ich.book(data);
$('#example').append(output);

ICanHaz.js fournit un objet ich et a créé une méthode book correspondant à l'id de la balise script. ICanHaz.js permet également de gérer les Mustache partielles de manière élégante en indiquant un attribut à la balise script. Si on remplace la partie edition par une Mustache partielle :

<script id="book" type="text/html">
Title: {{title}} <br/>
Author: {{author}} <br/>
{{> edition}}</script>

<script id="edition" type="text/javascript">
Edition: {{edition}}
</script>

l'appel à ich.book(data) reste le même !

Comme je vous le disais précédemment, ICanHaz.js gère un cache de templates et fournit donc des méthodes pour en rajouter dans le cache, le nettoyer ou le recharger.

VI - Conclusion et remerciements

Si, sur votre projet, vous utilisez jQuery et n'utilisez pas de système de template côté client, alors foncez ! Essayez Mustache.js et ICanHaz.js ! Le tout ne fait que 5,4 ko minifié.
Ensuite, je voudrais donner quelques précisions sur Mustache.js qui est en fait l'implémentation JavaScript du système de template Mustache (sans le .js). En effet, il existe de nombreuses implémentations de Mustache en Java, Ruby, Python, PHP, etc.
De plus, on dit souvent que Mustache est un système de template « logic-less », car il n'y a pas de if, else ou autre, il n'y a que des balises, que des moustaches :}}

VI-A - Remerciements

Cet article a été publié avec l'aimable autorisation de Ippon technologies. L'article original peut être vu sur le blog d'Ippon.

Nous tenons à remercier Didier Mouronval pour sa relecture attentive de cet article.