Bienvenue dans la deuxième partie de ce didacticiel. dans la première partie, nous avons examiné les bases du modèle, de la collection et de la vue pour l'utilisation de Backbone et avons vu comment restituer des vues de contact individuelles à l'aide d'une vue principale liée à une collection.
Dans cette partie du didacticiel, nous allons voir comment filtrer notre vue en fonction des entrées de l'utilisateur et comment ajouter un routeur pour donner à notre application de base une fonctionnalité d'URL..
Nous aurons besoin des fichiers source de la première partie, car nous allons nous appuyer sur le code existant pour cette partie. Je vous recommande fortement de lire la première partie si vous ne l'avez pas déjà.
Vous avez peut-être remarqué dans la première partie que chacun de nos modèles possède un type appelé attribut qui classe chaque modèle en fonction de son lien avec un ami, un membre de la famille d'un collègue. Ajoutons un élément select à notre vue principale pour permettre à l'utilisateur de filtrer les contacts en fonction de ces types..
Maintenant, nous pouvons coder un menu de sélection dans notre code HTML sous-jacent et ajouter manuellement des options pour chacun des différents types. Mais, cela ne serait pas très avant-gardiste; Et si nous ajoutions un nouveau type ultérieurement ou supprimions tous les contacts d'un certain type? Notre application n'a pas encore la capacité d'ajouter ou de supprimer des contacts (troisième partie alerte au spoiler!), Mais il est toujours préférable de prendre en compte ce genre de choses, même à ce stade précoce de notre application..
En tant que tel, nous pouvons facilement construire un élément de sélection de manière dynamique en fonction des types existants. Nous allons d’abord ajouter un petit peu de HTML à la page sous-jacente; ajoutez les nouveaux éléments suivants au conteneur de contacts:
Ça y est, nous avons un extérieur élément servant de conteneur général, dans lequel se trouve un autre conteneur avec une
identifiant
attribut, et un avec un texte explicatif.
Maintenant construisons le élément. Nous allons d’abord ajouter deux nouvelles méthodes à notre
DirectoryView
mater view; le premier extraira chaque type unique et le second construira le menu déroulant. Les deux méthodes doivent être ajoutées à la fin de la vue:
getTypes: function () return _.uniq (this.collection.pluck ("type"), false, fonction (type) return type.toLowerCase ();); , createSelect: function () var filter = this.el.find ("# filtre"), sélectionnez = $ ("", html:""); _.each (this.getTypes (), fonction (élément) var option = $ ("", valeur: item.toLowerCase (), texte: item.toLowerCase ()). appendTo (select);); return select;
La première de nos méthodes, getTypes ()
retourne un tableau créé avec Underscore uniq ()
méthode. Cette méthode accepte un tableau en tant qu'argument et renvoie un nouveau tableau contenant uniquement des éléments uniques. Le tableau que nous passons dans le uniq ()
la méthode est générée en utilisant le Backbone cueillir()
méthode, qui est un moyen simple d'extraire toutes les valeurs d'un seul attribut d'une collection de modèles. L’attribut qui nous intéresse ici est le type
attribut.
Afin d'éviter des problèmes de cas plus tard, nous devrions également normaliser les types en minuscules. Nous pouvons utiliser une fonction itérateur, fournie comme troisième argument de uniq ()
, pour transformer chaque valeur avant qu’elle soit passée au comparateur. La fonction reçoit l'élément actuel en tant qu'argument, nous renvoyons donc l'élément au format minuscule. Le deuxième argument passé à uniq ()
, que nous avons mis à faux
ici, un drapeau est-il utilisé pour indiquer si le tableau comparé a été trié.
La deuxième méthode, createSelect ()
est légèrement plus grand, mais pas beaucoup plus complexe. Son seul but est de créer et de retourner un nouveau element, afin que nous puissions appeler cette méthode ailleurs dans notre code et recevoir une nouvelle liste déroulante brillante avec une option pour chacun de nos types. Nous commençons par donner le nouveau
Nous utilisons ensuite Underscore chaque()
méthode pour parcourir chaque valeur du tableau retourné par notre getTypes ()
méthode. Pour chaque élément du tableau, nous créons un nouveau élément, définissez son texte sur la valeur de l'élément en cours (en minuscule), puis ajoutez-le à l'élément.
.
Pour rendre le élément de la page, nous pouvons ajouter du code à notre vue principale
initialiser()
méthode:
this. $ el.find ("# filtre"). append (this.createSelect ());
Le conteneur de notre vue principale est mis en cache dans la $ el
propriété que Backbone ajoute automatiquement à notre classe d'affichage. Nous l'utilisons donc pour rechercher le conteneur de filtre et ajouter le
Si nous courons la page maintenant, nous devrions voir notre nouveau élément, avec une option pour chacun des différents types de contact:
Alors maintenant, nous avons notre
événements: "change #filter select": "setFilter",
le événements
attribut accepte un objet de valeur clé
paires où chaque clé spécifie le type d'événement et un sélecteur auquel lier le gestionnaire d'événements. Dans ce cas, nous nous intéressons à la changement
événement qui sera tiré par le
Ensuite, nous pouvons ajouter le nouveau gestionnaire:
setFilter: function (e) this.filterType = e.currentTarget.value; this.trigger ("change: filterType"); ,
Tout ce que nous devons faire dans le setFilter ()
fonction est définie une propriété sur la vue principale appelée filterType
, que nous avons mis à la valeur de l'option qui a été sélectionnée, qui est disponible via le currentTarget
propriété de l'objet événement qui est automatiquement passé à notre gestionnaire.
Une fois que la propriété a été ajoutée ou mise à jour, nous pouvons également déclencher une changement
event for it en utilisant le nom de la propriété comme espace de noms. Nous verrons comment utiliser cet événement personnalisé dans un instant, mais avant cela, nous pouvons ajouter la fonction qui effectuera effectivement le filtre. après le setFilter ()
méthode ajouter le code suivant:
filterByType: function () if (this.filterType === "all") this.collection.reset (contacts); else this.collection.reset (contacts, silent: true); var filterType = this.filterType, filtré = _.filter (this.collection.models, function (item) retour item.get ("type"). toLowerCase () === filterType;); this.collection.reset (filtré);
Nous vérifions d’abord si la vue principale est filterType
la propriété est définie sur tout
; si c’est le cas, nous repeuplerons simplement la collection avec l’ensemble complet de modèles dont les données sont stockées localement sur notre ordinateur. Contacts
tableau.
Si la propriété n'est pas égale tout
, nous réinitialisons toujours la collection pour récupérer tous les contacts dans la collection, ce qui est nécessaire pour permuter entre les différents types de contact, mais cette fois, nous définissons la silencieux
option de vrai
(vous verrez pourquoi cela est nécessaire dans un instant) pour que le réinitialiser
événement n'est pas déclenché.
Nous stockons ensuite une version locale de la vue filterType
propriété afin que nous puissions la référencer dans une fonction de rappel. Nous utilisons Underscore filtre()
méthode pour filtrer la collection de modèles. le filtre()
La méthode accepte le tableau à filtrer et une fonction de rappel à exécuter pour chaque élément du tableau en cours de filtrage. La fonction de rappel est passé l'élément actuel en tant qu'argument.
La fonction de rappel retournera vrai
pour chaque article qui a un type
attribut égal à la valeur que nous venons de stocker dans la variable. Les types sont à nouveau convertis en minuscules, pour les mêmes raisons que précédemment. Tous les éléments renvoyés par la fonction de rappel faux
pour sont supprimés du tableau.
Une fois le tableau filtré, nous appelons le réinitialiser()
méthode encore une fois, en passant dans le tableau filtré. Nous sommes maintenant prêts à ajouter le code qui reliera le setType ()
méthode, la filterType
propriété et filterByType ()
méthode.
En plus de lier des événements d'interface utilisateur à notre interface à l'aide du événements
attribut, nous pouvons également lier les gestionnaires d’événements aux collections. Dans notre setFilter ()
méthode, nous avons déclenché un événement personnalisé, nous devons maintenant ajouter le code qui liera le filterByType ()
méthode pour cet événement; ajoutez le code suivant à la initialiser()
méthode de notre vue principale:
this.on ("change: filterType", this.filterByType, this);
Nous utilisons Backbone's sur()
méthode afin d'écouter notre événement personnalisé. Nous spécifions le filterByType ()
méthode en tant que fonction de gestionnaire pour cet événement en utilisant le deuxième argument de sur()
, et peut également définir le contexte de la fonction de rappel en définissant ce
comme troisième argument. le ce
objet se réfère ici à notre vue principale.
Dans notre filterByType
fonction, nous réinitialisons la collection afin de la repeupler avec tous les modèles ou les modèles filtrés. Nous pouvons également nous lier au réinitialiser
event afin de repeupler la collection avec des instances de modèle. Nous pouvons également spécifier une fonction de gestionnaire pour cet événement. Le plus grand avantage est que nous en avons déjà une. Ajoutez la ligne de code suivante directement après le changement
liaison d'événement:
this.collection.on ("reset", this.render, this);
Dans ce cas, nous écoutons pour le réinitialiser
événement et la fonction que nous souhaitons invoquer est la collection rendre()
méthode. Nous spécifions également que le rappel doit utiliser ce
(comme dans l'instance de la vue principale) en tant que contexte lors de son exécution. Si nous ne fournissons pas ce
comme troisième argument, nous ne pourrons pas accéder à la collection à l’intérieur du rendre()
méthode quand il gère la réinitialiser
un événement.
À ce stade, nous devrions maintenant constater que nous pouvons utiliser la zone de sélection pour afficher des sous-ensembles de nos contacts. La raison pour laquelle nous avons défini le silencieux
option à vrai dans notre filterByType ()
La méthode est telle que la vue ne soit pas rendue inutilement lorsque nous réinitialisons la collection au début de la deuxième branche du conditionnel. Nous devons faire cela pour pouvoir filtrer par un type, puis par un autre type sans perdre de modèle..
Donc, ce que nous avons eu jusqu'à présent est correct, nous pouvons filtrer nos modèles à l'aide de la zone de sélection. Mais ne serait-il pas génial de pouvoir également filtrer la collection à l'aide d'une URL? Le module de routeur de Backbone nous donne cette possibilité, voyons comment, et en raison de la manière bien découplée avec laquelle nous avons structuré notre filtrage jusqu'à présent, il est très facile d'ajouter cette fonctionnalité. Nous devons d’abord étendre le module routeur; ajoutez le code suivant après la vue principale:
var ContactsRouter = Backbone.Router.extend (routes: "filtre /: type": "urlFilter", urlFilter: fonction (type) directory.filterType = type; directory.trigger ("change: filterType"); );
La première propriété que nous définissons dans l'objet passé au routeur étendre()
la méthode est itinéraires
, ce qui devrait être un littéral d'objet où chaque clé est une URL à rechercher et chaque valeur à une fonction de rappel lorsque l'URL correspond. Dans ce cas, nous recherchons des URL commençant par #filtre
et finir avec autre chose. La partie de l'URL après le filtre/
une partie est passée à la fonction que nous spécifions en tant que fonction de rappel.
Dans cette fonction, nous définissons ou mettons à jour le filterType
propriété de la vue principale puis déclencher notre coutume changement
événement une fois de plus. C’est tout ce dont nous avons besoin pour ajouter une fonctionnalité de filtrage à l’aide de l’URL. Nous devons toutefois créer une instance de notre routeur, ce que nous pouvons faire en ajoutant la ligne de code suivante directement après la fin de la procédure. DirectoryView
instanciation:
var contactsRouter = new ContactsRouter ();
Nous devrions maintenant pouvoir entrer une URL telle que # filtre / famille
et la vue se re-rendra pour montrer uniquement les contacts avec la famille de types:
Donc c'est plutôt cool non? Mais il manque encore une partie: comment les utilisateurs sauront-ils utiliser nos belles URL? Nous devons mettre à jour la fonction qui gère les événements de l'interface utilisateur sur le serveur.
Pour ce faire, il faut deux étapes. Tout d'abord, nous devrions activer le support de l'historique de Backbone en démarrant le service d'historique après l'initialisation de notre application. ajoutez la ligne de code suivante à la fin de notre fichier de script (directement après l’initialisation de notre routeur):
Backbone.history.start ();
À partir de ce moment, Backbone surveillera l'URL des changements de hachage. Maintenant, lorsque nous voulons mettre à jour l'URL après que quelque chose se passe, nous appelons simplement le naviguer()
méthode de notre routeur. Changer la filterByType ()
méthode pour qu'il apparaisse comme ceci:
filterByType: function () if (this.filterType === "all") this.collection.reset (contacts); contactsRouter.navigate ("filter / all"); else this.collection.reset (contacts, silent: true); var filterType = this.filterType, filtré = _.filter (this.collection.models, function (item) return item.get ("type") === filterType;); this.collection.reset (filtré); contactsRouter.navigate ("filter /" + filterType);
Désormais, lorsque la boîte de sélection est utilisée pour filtrer la collection, l'URL est mise à jour et l'utilisateur peut alors mettre en signet ou partager l'URL, et les boutons Précédent et Suivant du navigateur permettent de naviguer entre les états. Depuis la version 0.5, Backbone prend également en charge l’API pushState. Toutefois, pour que cela fonctionne correctement, le serveur doit pouvoir afficher les pages demandées, que nous n’avons pas configurées pour cet exemple, et qui utilisent donc le module d’historique standard..
Dans cette partie du didacticiel, nous avons examiné quelques autres modules de Backbone, en particulier les modules Router, History et Events. Nous avons maintenant examiné tous les différents modules fournis avec Backbone..
Nous avons également examiné d'autres méthodes de soulignement, notamment filtre()
, que nous avons utilisé pour filtrer notre collection à seulement les modèles contenant un type spécifique.
Enfin, nous avons examiné le module Routeur de Backbone, qui nous permettait de définir des itinéraires pouvant être mis en correspondance par notre application afin de déclencher des méthodes, ainsi que le module Historique que nous pouvons utiliser pour mémoriser l’état et maintenir l’URL mise à jour avec des fragments de hachage..
Un point à retenir est la nature faiblement couplée de notre fonctionnalité de filtrage; Lorsque nous avons ajouté le filtrage via le menu de sélection, il était très facile et rapide de venir ensuite et d’ajouter une méthode de filtrage totalement nouvelle sans avoir à changer notre filtre()
méthode. C'est l'une des clés pour réussir à créer des applications JavaScript non triviales, maintenables et évolutives. Si nous le voulions, il serait très facile d’ajouter une autre méthode de filtrage totalement nouvelle, qui doit changer de méthode de filtrage..
Dans la prochaine partie de cette série, nous allons revenir à l'utilisation de modèles et voir comment nous pouvons les supprimer et en ajouter de nouveaux à la collection..