Vues de backbone et le DOM partie 2

Dans le dernier article, nous avons présenté les bases de Backbone Views et comment permettre à jQuery de manipuler de manière transparente le même DOM que Backbone..

Dans cet article, nous verrons comment faire en sorte que Backbone joue bien avec d3.js. Les concepts de cet article doivent s'appliquer aux situations dans lesquelles vous avez l'intention d'utiliser Backbone avec la plupart des autres bibliothèques qui manipulent également le DOM..

Backbone + d3.js travaillant sur le même DOM

d3.js, écrit par Mike Bostock, est une autre bibliothèque largement utilisée qui manipule le modèle objet de document, principalement pour visualiser des données. En fait, vous pouvez être vraiment créatif avec la façon dont les données peuvent être visualisées.

Au niveau le plus bas, d3.js interagit avec les éléments HTML et / ou SVG et manipule leurs attributs en liant les données au modèle d'objet document.

Voici un exemple rapide du fonctionnement de d3:

var numericalData = [1,2,3,4,5,6]; d3.select ("body"). selectAll ("p") .data (numericalData) .enter () .append ("p") .text (fonction (d) retourne "je suis un nombre" + d + " ! ";); 

Le code ci-dessus fait ce qui suit:

  1. Sélectionne et crée une référence à la corps élément
  2. Dans cette sélection, sélectionne tous les p éléments actuellement dans le DOM
  3. Ajoute chaque élément dans donnees numeriques à un sélectionné p élément
  4. Pour chaque p élément qui doit encore exister (c.-à-d. certains éléments de donnees numeriques qui doivent encore être ajoutés), crée un p élément et l'ajoute le DOM
  5. Définit le noeud de texte dans chaque nouvelle créé p élément contenant du texte (y compris le numéro correspondant dans donnees numeriques)

Une première tentative de faire dorsale et d3.js bien jouer

Tirant parti de ce que nous avons appris dans le précédent article, voici une implémentation d’une manipulation partagée du DOM.

var CoolView = Backbone.View.extend (render: function () var html = "

Je ne suis pas un nombre!

"; this. $ el.html (html); retour this;, renderVisualization: function (arrayOfData) d3.select (" body ") .selectAll (" p ") .data (arrayOfData) .enter () .append ("p") .text (fonction (d) retourne "je suis un nombre" + d + "!";);); var coolView = nouveau CoolView (); coolView.render (); var myData = [10, 9, 4, 2, 1]; coolView.renderWithD3 (myData);

Houston, nous avons un problème!

En supposant que notre objectif soit de préserver le p élément et ajouter l'autre p éléments de DOM, lorsque nous exécutons le code ci-dessus, nous rencontrons rapidement un problème majeur.

le .rendre() inserts une p élément avec le texte "je ne suis pas un nombre" dans le DOM. Mais .renderVisualization () sélectionne tous les existants p éléments dans le DOM et insère un contenu dans ces éléments. Ce écrase le texte de l'original p élément, malgré notre annexant au DOM en utilisant d3.append ().

Solutions pour que d3.js et le backbone jouent bien ensemble

Dans cet exemple simple, au moins deux solutions simples existent.

  1. Utilisez un sélecteur CSS plus spécifique
  2. Utilisez une balise complètement différente

Cordonner une partie du DOM

Pour des exemples plus complexes, nous aurons peut-être besoin de stratégies alternatives. Une solution potentielle consiste à isoler une partie du DOM qui sera exploitée par l'une des bibliothèques. Par exemple:

var CoolView = Backbone.View.extend (… renderVisualization: function (arrayOfData) d3.select ("# visualisation") .selectAll ("p") .data (arrayOfData) .enter () .append ("p") .text (fonction (d) retourne "je suis un nombre" + d + "!";);)); var coolView = new CoolView (); var myData = [10, 9, 4, 2, 1]; coolView.renderVisualization (myData); 

Dans le cas ci-dessus, Backbone continue de gérer la vue à créer. Cependant, disons qu’il existe un élément quelque part dans le DOM (à l’intérieur de ou en dehors du DOM géré par la vue Backbone) dont l’identifiant est «visualisation». Nous pouvons capitaliser sur ce fait en analysant toutes nos manipulations DOM liées à d3 à cet élément. En conséquence, toutes les méthodes en chaîne d3, y compris .selectAll ("p") et .append ("p"), sont exécutés dans le contexte de #visualisation.

Encapsulation de manipulations DOM différenciées avec des sous-vues

Enfin, une autre approche de la gestion des fonctionnalités d'affichage tierces consiste à utiliser des sous-vues. Voici à quoi cela pourrait ressembler.

var CoolView = Backbone.View.extend (render: function () var subViewA = new SubViewA (); var subViewB = new SubViewB (); // définit le contenu html pour coolview this. $ el.html (subViewA.render () .el); // ajoute plus de contenu HTML à coolview this. $ el.append (subViewB.render (). el); return this;); // Ailleurs, peut-être dans votre routeur… var coolView = new CoolView (); $ ('. app'). html (coolView.render (). el); 

Dans ce scénario, sous-vueA peut contenir du contenu non visuel, et subViewB peut contenir du contenu de visualisation.

Une autre approche de manipulation DOM partagée pour Backbone + d3.js

Il arrive parfois que vous deviez vous assurer que votre manipulation DOM d3 se produit dans le même contexte que la vue Backbone elle-même. Par exemple, il suffit de boucler une partie du DOM avec #visualisation n'offre aucune garantie que l'élément existe à l'intérieur ou à l'extérieur de la partie du DOM représentée par la vue Backbone.

Une alternative consiste à vous assurer que votre sélection de d3 de départ référence le même élément que celui indiqué par ceci. $ el. Cependant, si vous avez tendance à ne pas définir el ou l'un de ses attributs directement, il serait difficile de cibler suffisamment la vue actuelle à l'aide de CSS.

Heureusement, dans la bibliothèque d3.js, il existe une méthode permettant la sélection directe des nœuds. Permettez-moi de vous présenter à d3.select (noeud). Selon la documentation, cette méthode:

Sélectionne le noeud spécifié. Cela est utile si vous avez déjà une référence à un nœud, tel que d3.select (this) dans un écouteur d'événement, ou un élément global tel que document.body. Cette fonction ne traverse pas le DOM.

Cette méthode nous permet d’écrire le code suivant et d’assurer que les manipulations d3 se produisent dans le contexte de la vue Backbone..

var CoolView = Backbone.View.extend (// notez que "el" n'est pas défini directement. render: function () var html = "

Je ne suis pas un nombre!

"; this. $ el.html (html); return this;, renderVisualization: function (arrayOfData) d3.select (this); // ne fonctionnera pas," this "fait référence à un objet de réseau principal d3.select (this .el) // passe une référence de noeud .selectAll ("p") .data (arrayOfData) .enter () .append ("p") .text (fonction (d) retourne "I'm number" + d + "!";););

Conclusion

En résumé, il y a un certain nombre de considérations à prendre en compte pour que Backbone fonctionne bien avec d'autres manipulateurs DOM..

  1. Assurez-vous de sélectionner le bon élément à manipuler. L'utilisation de classes et d'identifiants CSS spécifiques peut rendre la vie beaucoup plus facile.
  2. Des utilisations intelligentes des différentes méthodes de manipulation du DOM dans l'une ou l'autre bibliothèque peuvent aller très loin. Assurez-vous de clarifier l'action DOM (ajouter, ajouter, ajouter, supprimer) dont vous avez réellement besoin.
  3. Les opérations en boucle dans le DOM peuvent être délicates. S'assurer que les bons éléments sont impactés.

Il existe également plusieurs solutions à envisager, en fonction du résultat recherché:

  1. Séparer une partie du DOM
  2. Portée de la manipulation DOM de l'autre bibliothèque vers le contexte Backbone
  3. Utilisation de sous-vues pour encapsuler l'impact d'autres manipulateurs DOM