Structurer son code jQuery avec Backbone.js
jQuery est une librairie géniale, mais en aucun cas un framework pour le développement.
Or, pour le développement d'applications - en particulier -, il est nécessaire de disposer d'une structure dans le code permettant une maintenance et une évolution future aisée.
Adopter une approche MVC est alors une bonne option et c'est ce que permet de faire Backbone.js
Pour tester notre code, il est également nécessaire d'utiliser la console javascript intégrée au navigateur.
Sous Google Chrome : Afficher / Options pour les développeurs / Console javascript
Backbone.js permet d'adopter une approche MVC, où l'on sépare l'affichage, l'accès aux données et ce qui fait le lien entre les 2.
La séparation permet de faire évoluer l'application sans devoir tout ré-écrire : un changement d'interface, une autre manière de récupérer les données dans la base etc.
http://fr.wikipedia.org/wiki/Mod%C3%A8le-Vue-Contr%C3%B4leur
De plus, Backbone propose par défaut une approche REST qui permet de simplifier les échanges avec le serveur sur les opérations de : création, modification et suppression.
http://fr.wikipedia.org/wiki/Representational_state_transfer
Backbone propose donc plusieurs “classes” dont voici les 3 principales :
View : ce sont les données affichées dans la page
Model : un objet chargé et manipulé, un utilisateur, un article dans un panier etc.
Collection : un ensemble de Model
Nous allons mettre en oeuvre ces 3 classes au travers d'un exemple simple : l'affichage d'une liste d'utilisateurs.
Préparation
Pour commencer, on récupère Backbone.js et underscore.js (et bien sûr jQuery ^^ ) http://backbonejs.org/ http://underscorejs.org/
Les répertoires de notre exemple seront organisés comme suit:
. index.html | js | libs . backbone-min.js . jquery.min.js . underscore-min.js | views . index.js
Dans la page index.html, on charge les scripts.
<!DOCTYPE html> <html lang="en"> <head> <meta charset="utf-8"> <title>tuto mediabox</title> </head> <body> <!-- on placera notre code HTML ici --> <!-- SCRIPTS --> <script type="text/javascript" src="js/libs/jquery.min.js"></script> <script type="text/javascript" src="js/libs/underscore-min.js"></script> <script type="text/javascript" src="js/libs/backbone-min.js"></script> <script type="text/javascript" src="js/views/index.js"></script> </body> </html>
On se place ensuite dans notre index.js
Le Model
Nous allons définir un Model qui se nomme User et qui correspond à un utilisateur. Par défaut, les utilisateurs ont tous le rôle “invite”, on le précise dans notre model Enfin, on instantie notre user
//model User var User = Backbone.Model.extend({ defaults : { "role" : "invité" } }) ; var user = new User({ id : 1, nom : 'david'}) ; console.log(user) ;
Dans la console javascript, une fois la page index.html affichée, on peut voir notre objet Model
attributes: Object id : 1 nom : "david" role : "invité"
Bien entendu, BB propose plusieurs fonctions pour manipuler les Models
user.set({'age': 37} ) ; //attribuer la valeur 37 à l'attribut age (et créer ce dernier s'il n'existe pas) user.get('age') ; //retourne la valeur de l'age
La Collection
La collection est un ensemble de modèle.
//création d'une collection du model User var UserCollection = Backbone.Collection.extend({ model : User }) ;
Dans le cadre de notre exercice, les données de la collection seront en dur.
Il y a plusieurs méthodes pour charger une collection, en voici une.
var dataColl = [ {id : 1, nom : "bob", age : 10}, {id : 2, nom : "patrick", age : 10}, {id : 3, nom : "carlo", age : 10} ]; var userColl = new UserCollection(dataColl) ; console.log(userColl.models) ;
En rafraichissant la page, on voit dans la console javascript les models de notre Collection …
Il est maintenant aisé de manipuler les Models dans notre Collection
userColl.get(1).get('nom') //retourne le nom de l’utilisateur 1 userColl.length ; //retourne le nombre d'éléments dans la Collection userColl.remove( userColl.get(1) ) ; //supprime celui qui porte l'id 1…
La View
On va à présent afficher la liste dans notre page HTML
Note : Il y a plusieurs manières de faire, voici une méthode qui considère que la vue est la liste, mais on peut également avoir une vue pour la liste ainsi qu'une vue par élément de cette liste. En fait, tout dépend du contexte, il n'y a pas de bonne solution unique.
Pour commencer, dans la page index.html, on crée notre liste qui porte l’id “user-ul”
<body> <div class="content"> <h1>Tutoriel Mediabox - backboneJS</h1> <div> <ul id="user-ul"></ul> </div> </div> ...
Dans le fichier index.js, on crée ensuite notre vue
var UserView = Backbone.View.extend({ el : '#user-ul', initialize : function () { console.log('vue créée'); console.log(this.$el); } }); // instantiation de la vue var userView = new UserView();
Dans notre vue, on défini l'élément HTML de cette dernière avec l'attribut “el”
L'objet View appelle systématiquement la méthode “initialize()”, dans laquelle nous allons pouvoir charger la liste
Enfin, on instantie la vue
Reste à présent à mettre en musique la vue, le model et la collection
Mais avant cela, un petit aparté sur les templates
Pour le rendu de notre liste, on peut simplement créer une chaine de caractère HTML en itérant dans les objets de la collection, on aura quelque chose dans ce goût là
var htmlString = '', user = {}; for (var i = 0, ii = collection.length; i < ii ; i++) { user = collection.get(i); htmlString += '<li>' + user.get('nom') + </li>'; } $('#user-ul').html( htmlString );
Le problème de cette méthode est qu'on utilise des balises HTML dans le code JS, si on décide d'afficher les utilisateurs dans une table au lieu d'un liste, il faudra alors modifier le code javascript.
Pour éviter cela, on va utiliser un template et ça tombe bien, underscroreJS propose sont propre système !
http://underscorejs.org/#template
La première chose à faire est donc de créer son template dans la page HTML (on peut externaliser les templates, mais ça n'est pas l'objet de ce tutoriel
Voici comment définir une template underscoreJS
<script type="text/template" id="user-row-tpl"> <li data-id="<%= id %>"><%= nom %> ( <%= role %> )</li> </script>
Il suffit ensuite de passer à ce template un objet contenant les attributs id, nom et role pour le charger
Vous comprenez maintenant mieux la souplesse si on devait charger les users dans une table.
<script type="text/template" id="user-row-tpl"> <tr> <td data-id="<%= id %>"><%= nom %> ( <%= role %> )</td> </tr> </script>
Pour finir, on utilise le template dans notre vue
J'ai essayé de commenter au mieux le code ci-dessous
var UserView = Backbone.View.extend({ el : '#user-ul', initialize : function () { // instantiation de la collection en lui passant le tableau des users this.coll = new UserCollection(dataColl); // référence au template this.template = _.template($('#user-row-tpl').html()); appelle le rendu de la vue pour afficher la liste this.render(); }, render : function () { var html = '', that = this; // itération dans la collection et création du HTML this.coll.each(function (user) { html += that.template(user.attributes); }); // on insère le HTML dans l'élément HTML qui constitue notre vue this.$el.html(html); } });
Si tout ce passe bien, vous devriez avoir dans votre page HTML la liste des users !
Si non, voici le code complet
La page HTML
<body> <div class="content"> <h1>Tutoriel Mediabox - backboneJS</h1> <div> <ul id="user-ul"></ul> </div> </div> <!-- TEMPLATES --> <script type="text/template" id="user-row-tpl"> <li data-id="<%= id %>"><%= nom %> ( <%= role %> )</li> </script> <!-- SCRIPTS --> <script type="text/javascript" src="js/libs/jquery.min.js"></script> <script type="text/javascript" src="js/libs/underscore-min.js"></script> <script type="text/javascript" src="js/libs/backbone-min.js"></script> <script type="text/javascript" src="js/views/index.js"></script> </body>
Le script index.js
(function ($) { // bootstrap data var dataColl = [ {id : 1, nom : "bob", age : 10}, {id : 2, nom : "patrick", age : 10}, {id : 3, nom : "carlo", age : 10} ]; // le model var User = Backbone.Model.extend({ defaults : { "role" : "invité" } }) ; // la collection var UserCollection = Backbone.Collection.extend({ model : User }) ; // la vue var UserView = Backbone.View.extend({ el : '#user-ul', initialize : function () { this.coll = new UserCollection(dataColl); this.template = _.template($('#user-row-tpl').html()); this.render(); }, render : function () { var html = '', that = this; this.coll.each(function (user) { html += that.template(user.attributes); }); this.$el.html(html); } }); var userView = new UserView(); })(jQuery);
les évènements
Pour mettre un peu d'interactivité, nous allons écouter les click sur les éléments de la vue.
Le click sur un user affichera sont id dans une alert()
Pour placer des écouteurs dans notre View, on utilise l'attribut “events” :
Voici la vue modifiée
var UserView = Backbone.View.extend({ el : '#user-ul', initialize : function () { this.coll = new UserCollection(dataColl); this.template = _.template($('#user-row-tpl').html()); this.render(); }, events : { 'click li' : 'clickHandler' }, clickHandler : function (e) { alert($(e.currentTarget).data('id')); }, render : function () { var html = '', that = this; this.coll.each(function (user) { html += that.template(user.attributes); }); this.$el.html(html); } });
Conclusion
Et voilà, nous avons à présent un code clair et séparé qui nous permet une grande souplesse
Dans le prochain tutoriel, nous verrons la connexion à un serveur pour ajout, modification et suppression des users
