Présentation
Introduction
Backbone.js est un framework JavaScript basé sur la librairie Underscore.JS. Il permet de structurer une application web, non plus comme une suite d’instructions jQuery, mais comme un assemblage de vues autonomes les unes des autres.
Son but est de poser des bases fortes pour développer des applications riches, sans pour autant imposer une structure applicative.
Il se veut non-contraignant par rapport à ses rivaux, ce qui lui coûte d’être présenté souvent comme moins complet. Son point fort est d’être facilement utilisable avec d’autres librairies ou frameworks.
Ses dépendances
Backbone.js est basé sur la librairie Underscore.JS. Cette dernière propose des fonctionnalités de manipulation d’objets, de collections et de tableaux assez poussées. Comme toute librairie populaire, elle se veut cross-browser et par héritage, Backbone.JS l’est aussi.
Pour tout ce qui est manipulation DOM, plutôt que réinventer la roue, l’équipe en charge de Backbone.JS a décidé de sous traiter cette tâche à jQuery. Il est possible de remplacer jQuery, par exemple avec Zepto, du moment qu’elle respecte l’api jQuery-compatible.
Les composants
Backbone.JS fournit des composants logiciels pouvant être utilisés librement, que ce soit avec les autres composants Backbone.JS ou avec une autre librairie. Les trois plus importants sont le Model, la Collection et la View.
On parlera également de deux composants moins importants mais qui fournissent des fonctionnalités très intéressantes : Router et Sync.
L’utilisation de chaque composant se fait par extension de la classe. Lors de l’extension, il est possible de réimplémenter les méthodes ou de redéfinir les attributs et ainsi paramétrer l’objet pour que son comportement corresponde à nos attentes. La documentation est très bien fournie sur ce point qui se trouve être, à mon sens, un des points forts de Backbone.JS.
var ExtendClass = Backbone.Model.extend({ initialize: function() { ... } });
Les données
Backbone.Model
La classe Backbone.Model est utilisée pour gérer du contenu sous la forme d’un objet JavaScript en l’encapsulant et en proposant des méthodes accesseurs.
var Article = Backbone.Model.extend({}); var article = new Article({ title: 'New Article' }); article.get('title'); // New Article article.set('title', 'New title'); article.get('title'); // New title
Testez ce code en ligne sur jsfiddle
Backbone.Collection
La classe Backbone.Collection permet de manipuler des collections de Model. On retrouve les méthodes habituelles : push, pop, shift, unshift, add, remove, get, sort ou encore length. On retrouve également les fonctions provenant de Underscore.JS.
var Article = Backbone.Model.extend({}); var Articles = Backbone.Collection.extend({ model : Article }); var articles = new Articles([{ title: 'Article 1' },{ title: 'Article 2' },{ title: 'Article 3' }]); articles.push(articles.shift()); articles.models = articles.shuffle();
Testez ce code en ligne sur jsfiddle
Backbone.Sync
Concrètement, jusque là, nous avons vu comment manipuler des données. Mais pourquoi s’embêter avec alors que nous pourrions le faire plus simplement? C’est Sync qui va vous apporter la réponse.
Sync est le composant permettant de synchroniser les objets à travers une API du type RESTful JSON. Pour cela, il suffit de lier les objets Model et Collection à une ressource grâce à l’attribut url.
var urlModel = 'http://ippon.fr/articles/1'; var urlCollection = 'http://ippon.fr/articles'; var Article = Backbone.Model.extend({ url: urlModel; }); var Articles = Backbone.Collection.extend({ model: Article, url: urlCollection });
Testez ce code en ligne sur jsfiddle
La vue
Comme je l’ai signalé au début de l’article, Backbone.JS a pour but de poser les bases du développement MVC en JavaScript. Backbone.View. C’est pourquoi, pour toutes les manipulations DOM, on retrouve le plugin jQuery qui est de loin, le mieux armé pour ces opérations.
Backbone.View
Chaque objet Backbone.View est lié à un nœud DOM (el) et pourra le générer à nouveau, à n’importe quel moment. Le but est alors de découper le document en une multitude de vues que l’on pourra regénérer à souhait et individuellement.
var View = Backbone.View.extend({ render: function() { $(this.el).html(new Date().toLocaleTimeString()); return $(this.el); } }); var view = new View();
- Vue liée au DOM : Testez en ligne sur jsfiddle
- DOM lié à la Vue : Testez en ligne sur jsfiddle
Ces deux techniques ont leurs avantages et leurs inconvénients. Pour ma part, je préconise la deuxième solution.
Les événements
Backbone.View permet de gérer les événements d’un nœud assez simplement. Munissez-vous de l’action souhaitée et du sélecteur, et le tour est joué.
var View = Backbone.View.extend({ render: function() { $(this.el).html(this.template); return $(this.el); }, events: { 'click #button1' : 'onClickButton1', 'hover .button2' : 'onHoverButton2' }, onClickButton1 : function() { alert('button1'); }, onHoverButton2: function() { alert('button2'); } });
Exemple complet
Maintenant que vous connaissez les grandes lignes de Backbone.JS, il est temps de vous fournir un exemple utilisant tous les composants vus précédemment.
Libre à vous de vous amuser à rajouter des fonctionnalités.
Pour aller plus loin
Gestion des routes
Maintenant que nous pouvons réaliser des pages web composées de Backbone.View, peut-on aussi facilement gérer les différents états d’une page et y lier une URL ?
Si j’évoque le sujet, il est évident que la réponse est positive. Backbone.Router permet de mettre en place cette démarche. Une URI est composée d’un nom de domaine (tatami.ippon.fr) et d’une ressource (/tatami/). Il est possible de rajouter à la suite une ancre délimitée par une dièse (#/timeline). C’est cette ancre que Backbone.Router utilise pour déterminer quel est l’état de la page demandée.
Pour illustrer ces propos, une fois authentifié sur la page d’accueil de Tatami, chaque onglet représente un état de la page. Il en existe 5 actuellement :
- “#/timeline”, la page avec l’onglet “Status” affiché
- “#/favoris”, la page avec l’onglet “Favoris” affiché
- “#/tags”, la page avec l’onglet “Tags” affiché
- “#/search”, la page avec l’onglet “Recherche” affiché
- “#/daily”, la page avec l’onglet “Status du jour” affiché
Source du router home de Tatami
Asynchronous Module Definition API
Il est possible d’utiliser Backbone.JS avec un AMD Loader comme RequireJS ou Curl. Ni Backbone.JS, ni Underscore ne supportent officiellement AMD. Toutefois, il est possible d’utiliser un fork implémentant de cette API.
On trouve sur Github des projets templates (boilerplate) qui facilitent la mise en place d’un environnement couplant RequireJS et Backbone. En voici deux parmi tant d’autres :
Plugins
Backbone.JS se veut léger : il ne fournit que des composants essentiels. Un des gros manquements de Backbone.JS par rapport à ses concurrents est l’absence de la fonctionnalité de DataBinding. Mais qu’à cela ne tienne, de nombreux plugins sont présents en libre accès sur GitHub, pour implémenter des fonctionnalités. Voici, quelques plugins que je trouve intéressants :
- Backbone.ModelBinder : implémentation du DataBinding.
- Backbone.Marionette : collection de composants additionnels.
- Backbone.localStorage : adaptateur localstorage
Conclusion
Je me suis occupé de la migration de Tatami vers une interface utilisant Backbone.JS, et son utilisation s’est révélée être très agréable et facilitée lorsqu’on le couple à une API RESTful JSON.
Vous pouvez accéder au code source de Tatami et voir comment Backbone.JS peut être utilisé dans un projet.
Par rapport à l’existant post-Backbone, la nouvelle version est plus claire, plus structurée. Elle respecte également la séparation modèle/vue et est modulaire, facilitant ainsi sa maintenance.
Pour aller plus loin, je vous conseille de lire sur cet article qui explique les différentes étapes qui permettent de passer d’une application full-jQuery à une application utilisant Backbone.JS.