Les routeurs dans Backbone.js

Publié le 3 septembre 2013 par François Vaux | front

Cet article est publié sous licence CC BY-NC-SA

Dans cet article, nous allons expliquer le fonctionnement et l’utilité des routeurs de Backbone.js. Nous reprendrons le code de l’article Débuter avec Backbone.js comme base.

Les utilisateurs de notre application peuvent déjà naviguer en cliquant sur les différents noms de contact, mais ça se résume à ça.

On voudrait pouvoir faire en sorte que chaque contact ait sa propre URL, de façon à pouvoir y accéder directement par un lien.

C’est là l’utilisation principale des routeurs : fournir une gestion des URLs à notre application JavaScript.

Ce mécanisme se fait en priorité grâce à l’History API pour les navigateurs la supportant, ou en dégradant vers des hash fragments (#un/chemin) si ce n’est pas le cas.

Préparation de l’application

Dans notre précédente version du code, nos différents composants n’étaient pas namespacés, vous pouvez récupérer sur le dépôt GitHub une nouvelle version du code ou tous les composants sont dans un namespace app.

Ceci nous facilitera le travail par la suite, et c’est une bonne habitude à prendre dans vos développements.

Spécifications

Dans notre cas, nous souhaitons avoir deux types d’URLs :

  • contacts/:id qui permet d’avoir un lien direct vers la fiche d’un contact ;
  • contacts/search/:pattern pour avoir un lien vers le résultat d’une recherche.

Afin d’implémenter cela, on va ajouter un routeur à notre application et modifier quelques vues.

Mise en place du routeur

Dans un fichier js/routers/application_router.js, on écrit le code suivant :

var app = app || {};

app.ApplicationRouter = Backbone.Router.extend({
  routes: {
    "contacts/search/:pattern": "filterContact",
    "contacts/:id":             "showContact",
  },

  showContact: function(id) {
    var contact = app.Contacts.get(id);

    app.MainView.showContact(contact);
  },

  filterContact: function(pattern) {
    app.MainView.contactList.filter(pattern);
  }
});

Décortiquons ce code !

On déclare tout d’abord un ensemble de routes, en utilisant une notation similaire à celle utilisée pour les évènements dans les vues.

La notation est assez classique, surtout si vous avez déjà fait du Rails ou du Sinatra. Les parties de l’URL précédées d’un : permettent de spécifier les parties variables de nos URLs.

Notez qu’on peut très bien déclarer contacts/:id en premier sans craindre qu’elle prennent le dessus sur contacts/search/:pattern car les portions variables ne peuvent pas contenir de /.

Chaque route est liée à une méthode de notre routeur.

Chaque méthode doit permettre de placer l’application dans l’état correspondant à la route affichée.

Ici chaque méthode appelle simplement les méthodes déjà implémentées de nos vues.

Chargement et initialisation

Dans notre fichier index.html, on ajoute une ligne pour charger le fichier du routeur après les autres déclarations <script>, puis on modifie la partie qui initialise l’appliation comme suit :

var app = app || {};

$(function() {
  app.Contacts = new app.ContactBook();
  app.MainView = new app.AppView(app.Contacts);
  app.Router   = new app.ApplicationRouter();

  Backbone.history.start();
});

Note : nous avons changé le nom de certains composants pour améliorer la lisibilité du code

On initialise donc simplement notre routeur puis on appelle Backbone.history.start.

Cette dernière va analyser l’URL courante du document et faire appel au routeur pour lancer les actions adéquates.

Vous pouvez passer à start l’argument {pushState: true} pour utiliser l’History API. Nous ne le faisons pas dans notre cas car l’application n’est pas servie correctement par un domaine mais accédée via une URL file//. L’History API n’est pas compatible avec ce mode d’ouverture des fichiers.

Si vous lancez l’application maintenant, vous ne remarquerez aucun changement notable car on ne définit jamais l’URL correspondant à une partie de l’application. C’est donc ce que nous allons ajouter maintenant.

Définir les URLs

Une URL correspond en fait à un état de l’application.

Ici on va changer d’URL à l’affichage d’un contact et à la modification du champ de recherche.

Pour définir l’URL on utilise Router#navigate en passant l’URL en argument.

Notre routeur étant stocké dans app.Router, on modifie les méthodes AppView#showContact et ContactListView#filter en conséquence :

// js/models/app_view.js
  showContact: function(contact) {
    app.Router.navigate('contacts/' + contact.id);
    // ...
  },

// js/models/contact_list_view.js
  filter: function(contact) {
    app.Router.navigate('contacts/search/' + encodeURIComponent(text));
    // ...
  },

Ainsi, à chaque appel de ces méthodes, l’URL sera définie automatiquement.

Vous pouvez maintenant relancer l’application et observer comment la barre d’adresse est modifiée à chaque sélection d’un contact ou à chaque modification du champ de recherche.

Vous pouvez aussi copier l’adresse et l’ouvrir dans un nouvel onglet : vous arriverez alors directement au même endroit de l’application.

Conclusion

Le routage dans Backbone est très léger mais très puissant, tout comme on a l’habitude avec le reste de cette bibliothèque.

L’exemple présenté ici est évidemment simple, mais vous pouvez maintenant essayer de rajouter des fonctionnalités à ce carnet d’adresses pour exploiter pleinement les fonctionnalités de Backbone.

Dans le prochain article, nous ajouterons un vrai backend à notre application.