16

Tengo una pregunta, cosas realmente básicas, creo, pero:Backbone: ¿varias vistas se suscriben al evento de una sola colección? ¿Es esto una mala práctica?

Solo he visto ejemplos con una vista de colección y una vista única que dependen de una colección que se está actualizando. ¿Qué sucede si tiene múltiples vistas tratando de suscribirse a un evento de colecciones, es decir, reset, addOne, addAll etc ...

¿Me falta algún punto acerca de hacer/no hacer esto? ¿Tienes algún ejemplo de esto? ¿Eso tiene sentido?

Cualquier información Se aprecia mucho la

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}); 

Respuesta

30

Lo que está haciendo es perfectamente bien y parte de la razón para el uso de la espina dorsal. Desde el Backbone introduction:

Siempre que una acción de interfaz de usuario hace que un atributo de un modelo para que cambie, el modelo provoca un "cambio" caso ; todas las Vistas que muestran el estado del modelo pueden ser notificadas del cambio,

Tenga en cuenta que dicen "todas las Vistas", no "la vista".

Un ejemplo de vistas múltiples para una sola colección sería un sistema de chat. Supongamos que tiene una colección de usuarios que están en línea; entonces es posible que tenga un punto de vista simple en la cabecera que muestra el número de personas que están en línea y otro punto de vista (de la misma colección) que enumera los usuarios:

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; 
    } 
}); 

entonces tendría una OnlineUsers ejemplo, pero ambos sus instancias CounterView y ListView lo estarían viendo. Cuando las personas se conectan o se desconectan, ambas vistas se actualizarán según lo desee.

demostración simple: http://jsfiddle.net/ambiguous/eX7gZ/

La situación ejemplo anterior suena exactamente el tipo de cosas que estás haciendo y es exactamente el tipo de cosa que es para Backbone. Buen trabajo.

+1

Gracias por la respuesta, tiene sentido! –

2

Tuvimos el mismo problema. Necesitábamos usar múltiples plantillas de jQuery con eventos internos únicos para cada modelo sin usar múltiples vistas de titular. Esta es la solución que se nos ocurrió:

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... 
     }); 
    } 
}); 

fuente completo y ejemplo de trabajo: http://jsfiddle.net/HLv5z/9/

Cuestiones relacionadas