16

Ho una domanda, roba davvero semplice, ma penso:Backbone: visualizzazioni multiple che si iscrivono all'evento di una singola raccolta? È una cattiva pratica?

Ho visto solo esempi con una vista di raccolta e una vista singola dipendente da una collezione in fase di aggiornamento. Che cosa succede se si dispone di più viste che tentano di iscriversi a eventi di una raccolta, vale a dire reset, addOne, addAll ecc ...

Mi manca qualche punto sul fare/non farlo? Avete qualche esempio di questo? Ha senso?

Qualsiasi info è molto apprezzato

var Coll = Backbone.Collection.extend({ 
     model: SingleModel, 
     url: 'service', 
     initialize: function(){ 
      console.log('collection inited') 

     }   

    }); 

    var SingleModel = Backbone.Collection.extend({});    

    var CollView = Backbone.View.extend({     
     el: 'ul', 
     template: Handlebars.compile(someContainerTemplate), 
     init: function(){ 
      _.bindAll(this, 'render', 'addAll', 'addOne'); 
      this.collection.bind("reset", this.addAll); 

      this.collection.fetch(); 
     }, 
     render: function(){ 
      $(this.el).append(this.template()) 
     }, 

     addAll: function(){ 
      this.collection.each(this.addOne); 
     }, 

     addOne: function(model){ 
      var view = new SingleView({ model: model })    
     } 
    }) 

    var SingleView = Backbone.View.extend({ 
     tagName: "li", 
     events: { 
      "click .delete": "remove"      
     }, 
     template: Handlebars.compile(someTemplateForSingleItem), 
     initialize: function() { 
     _.bindAll(this,'render'); 

      this.model.bind('save', this.addOne); 
      this.model.bind('destroy', removeEl); 
     }, 

     remove: function(){ 
      this.model.destroy(); 
     }, 

     removeEl: function(){ 
      $(this.el).remove(); 
     }, 

     render: function() { 
      var context = this.model.toJSON(); 
      return $(this.el).append(this.template(context)); 
     },  
    }) 


    // standard so far (excluding any bad practices), 
    // but what if you have another view dependent on 
    // say the number of length of the collection, and 
    // you want it to update if any single models are destroyed 

    var HeaderView = Backbone.View.extend({ 
     tagName: "div#header", 
     template: Handlebars.compile(someHeaderTemplate), 
     initialize: function() { 
     _.bindAll(this,'render'); 

     this.model.bind('save', this.addOne); 
     }, 

     render: function() { 
      //assigning this collection length 

      var context = this.collection.length; 
      return $(this.el).append(this.template(context)); 
     },  
    });   

    var coll = new Coll(); 
    new CollView({ collection: coll }); 
    new HeaderView({ collection: coll}); 

risposta

30

Quello che stai facendo è perfettamente bene e parte della ragione per l'utilizzo Backbone. Dal Backbone introduction:

Ogni volta che un'azione di interfaccia provoca un attributo di un modello per cambiare, il modello innesca un "cambiamento" evento ; tutte le viste che visualizzano lo stato del modello possono essere notificati del cambiamento,

Nota che dicono "tutte le Visualizzazioni", non "la vista".

Un esempio di più viste per una singola raccolta sarebbe un sistema di chat. Supponiamo che tu abbia una collezione di utenti online; allora si potrebbe avere un semplice vista nell'intestazione che visualizza il numero di persone che sono in linea e un'altra vista (della stessa collezione), che elenca gli utenti:

var User = Backbone.Model.extend({}); 
var OnlineUsers = Backbone.Collection.extend({ 
    model: User 
}); 

var CounterView = Backbone.View.extend({ 
    tagName: 'span', 
    initialize: function() { 
     _.bindAll(this, 'render'); 
     this.collection.on('add', this.render); 
     // other interesting events... 
    }, 
    render: function() { 
     this.$el.text(this.collection.size()); 
     return this; 
    } 
}); 
var ListView = Backbone.View.extend({ 
    initialize: function() { 
     _.bindAll(this, 'render'); 
     this.collection.on('add', this.render); 
     // other interesting events... 
    }, 
    render: function() { 
     var html = this.collection.map(function(m) { 
      return '<p>' + m.get('name') + '</p>'; 
     }); 
     this.$el.html(html.join('')); 
     return this; 
    } 
}); 

Poi si avrebbe uno OnlineUsers grado, ma sia le tue istanze CounterView e ListView lo guarderebbero. Quando le persone arrivano online o non sono in linea, entrambe le visualizzazioni verranno aggiornate come desiderato.

semplice demo: http://jsfiddle.net/ambiguous/eX7gZ/

La situazione esempio precedente suona come esattamente il genere di cosa che stai facendo e che è esattamente il tipo di cosa che Backbone è per. Buon lavoro.

+1

Grazie per la risposta, ha un senso! –

2

Abbiamo avuto lo stesso problema. Avevamo bisogno di utilizzare più modelli jQuery con eventi interni unici per ogni modello senza utilizzare più visualizzazioni titolare. Questa è la soluzione che abbiamo fornito:

var myHolderView = Backbone.View.extend({ 
    el: '#views', 
    render: function(){ 
     // This is because 'this' change inside the collection.each 
     var $this = this; 

     // If you want a wrapper template 
     var wrapperHtml = $('#view-wrapper-template').tmpl(); 
     $this.$el.append(wrapperHtml); 
     $wrapper = $this.$el.find('> div'); // If wrapper is a div 


     $this.collection.each(function(model){ 
      // Render and append the viewA with internal events 
      var viewA = new myViewA({model: model}); 
      viewA.render(); 

      // Use this to add the views content (viewA.el) to this views element ('#views') 
      //$this.$el.append(viewA.el); 

      // Use this to add the view content (viewA.el) to this views wrapper element ($wrapper) 
      $wrapper.append(viewA.el); 


      // Render and append the viewB with internal events 
      var viewB = new myViewB({model: model}); 
      viewB.render(); 
      //$this.$el.append(viewB.el); 
      $wrapper.append(viewB.el); 


      // Add more views here... 
     }); 
    } 
}); 

sorgente completo e l'esempio di lavoro: http://jsfiddle.net/HLv5z/9/