Riot et Backbone, combo magique?

Ma nouvelle étape dans ma découverte de Riot est: “est-ce que ça fonctionne correctement avec Backbone?”. En effet je préfère (mais ça n’engage que moi) travailler avec plusieurs “microframeworks” qu’un seul “macroframework” qui lorsqu’il disaparaît ou change profondément vous colle dans la mouise. Sans compter ma passion immodérée pour Backbone ;).

Modifions notre code serveur

Si vous êtes ici, c’est que normalement vous avez lu le post précédent http://k33g.github.io/2015/02/02/RIOT.html

Donc modifiez le code du fichier app.js de cette façon:

var express = require('express');
var http = require('http');
var bodyParser = require('body-parser');

var app = express(), http_port = 3008;

app.use(express.static(__dirname + '/public'));

app.use(bodyParser.urlencoded({
  extended: true
}));
app.use(bodyParser.json());

/* on ajoute une mini base de données en mémoire */
var db = [
  {id: "001", firstName:"Bob", lastName:"Morane"},
  {id: "002", firstName:"John", lastName:"Doe"},
  {id: "003", firstName:"Jane", lastName:"Doe"}
];

/* envoyer la liste des humains au format json */
app.get("/humans", function(req, res) {
  res.send(db)
});

app.listen(http_port);
console.log("Listening on " + http_port);

Ajoutons les dépendances

Nous aurons besoin de:

Vous collez tout ça dans le répertoire js/vendors

votre-app/
├── public/ 
|   ├── js/ 
|   |   ├── tags/     
|   |   |    └── hello-title.tag            
|   |   └── vendors/ 
|   |        ├── backbone.js    
|   |        ├── underscore.js    
|   |        ├── jquery-2.1.3.min.js            
|   |        ├── riot.js    
|   |        └── compiler.js      
|   └── index.html
├── package.json    
└── app.js

C’est bon, nous somme prêts pour continuer.

Pensez à déclarer les dépendances dans la page index.html:

<script src="js/vendors/jquery-2.1.3.js"></script>
<script src="js/vendors/riot.js"></script>
<script src="js/vendors/compiler.js"></script>
<script src="js/vendors/underscore.js"></script>
<script src="js/vendors/backbone.js"></script>

La liste des humains: version simple

Lancez déjà votre application node app.js et appelez http://localhost:3008/humans pour vérifier que vous obtenez bien un tableau de données:

[{"id":"001","firstName":"Bob","lastName":"Morane"},{"id":"002","firstName":"John","lastName":"Doe"},{"id":"003","firstName":"Jane","lastName":"Doe"}]

Dans index.html

Dans le corps de la page ajoutez le tag <humans-list></humans-list>

Au sein d’une balise <script></script> en bas de page, ajoutez le code Backbone qui va bien:

var Kind = function() {};
Kind.extend = Backbone.Model.extend;

var HumansServices = Kind.extend({
   constructor: function() {
       var Human = Backbone.Model.extend({
          urlRoot: "humans"
       });
       var Humans = Backbone.Collection.extend({model: Human, url:"humans"});

       this.humansColl = new Humans()
   }
});

var humansServices = new HumansServices();

/* Monter humans-list en lui passant le service */

riot.mount("humans-list",{
  humansServices: humansServices
});

Création du tag humans-list

Ensuite, créez un nouveau tag dans le répertoire public/js/tags que vous appelerez humans-list.tag

<humans-list>
    <div each="{humans}">
        {id} {firstName} {lastName}
    </div>

    var thatList = this;
    var humansCollection = this.opts.humansServices.humansColl;

    humansCollection.fetch().then(function() {
        thatList.humans = humansCollection.toJSON();
        thatList.update()
    });

</humans-list>

Pensez à le déclarer dans index.html:

<script src="js/tags/humans-list.tag" type="riot/tag"></script>

Et voilà, vous n’avez plus qu’à tester dans votre navigateur:

Jusque là pas de soucis, vérifions un deuxième point.

La liste des humains: version “nested”

Il est intéressant parfois de ne vouloir modifier (et afficher les modifications) qu’un seul modèle de la liste sans avoir à recharger toute la liste (surtout si elle est longue).

Nouveau tag human-card

Du coup créons un nouveau tag dans public/js/tags que nous appellerons human-card.tag qui servira à afficher le détail d’un modèle:

<human-card>
    <div>{human.firstName} {human.lastName}</div>

    var thisCard = this;
    this.model = this.opts.model; /* je passe le modèle Backbone en options */
    this.human = this.model.toJSON()

    /* si mon modèle change, je mets à jour l'affichage */
    this.opts.model.on("change", function(){
        thisCard.human = thisCard.model.toJSON()
        thisCard.update();
    });
    
</human-card>

Allons modifier le tag humans-list

<humans-list>
    <div each="{model, index in humans}">
        <human-card model={model}></human-card>
    </div>

    var thatList = this;
    var humansCollection = this.opts.humansServices.humansColl;

    humansCollection.fetch().then(function() {
        thatList.humans = humansCollection.models;
        thatList.update()
    });

</humans-list>

Vous avez noté que l’on passe le modèle par le biais d’un attribut model (model n’est pas un mot clé, je l’ai choisi moi même).

Pensez à déclarer le nouveau tag dans index.html:

<script src="js/tags/human-card.tag" type="riot/tag"></script>
<script src="js/tags/humans-list.tag" type="riot/tag"></script>

Testez à nouveau dans votre navigateur: vous obtiendrez la même chose que toute à l’heure, mais par contre, ouvrez la console et tapez la commande suivante:

humansServices.humansColl.at(0).set("firstName","BOBBY")

Vous prenez donc le 1er modèle de la collection et changez la valeur de firstName, à ce moment là, le trigger "change" du modèle est déclenché et l’affichage du modèle est mis à jour:

Donc pour le moment, la cohabitation avec mon framework fétiche et Riot semble se passer plutôt pas mal. Il va falloir continuer de creuser, mais je suis plutôt optimiste.

I <3 Riot ;)

blog comments powered by Disqus

Related posts