Search code examples
backbone.jsbackbone-eventsbackbone.js-collections

BackboneJs - Retain events on a collection inside a model when model changes


i've a Collection inside a Model as illustrated below:

var itemModel = Backbone.Model.extend({

   defaults:{
      name:"",
      brand:"",
      priceCollection:[]
    }
})

There are change listeners attached to the itemModel and also change listeners attached to collection as this.listenTo(itemModel.get('priceCollection'),'change',this.dosomething) in a view.

The problem is that the change listeners on the collection work fine as long as the parent model hasn't changed , if the model is given a set of new attributes via itemModel.set(newattributes) the event bound on itemModel.get('priceCollection') is lost.

How do i retain this event? or should i rebind this event everytime the Model is change? or Should i move the listener on the collection from the view to the Model and trigger a custom Backbone event?

It should be noted that this model is singleton


Solution

  • Keep in mind that Backbone assumes a Collection and Model should be mapped 1:1 to a server side resource. It makes clear assumtions on the API layout and data structures - refer to Model.url, Model.urlRoot and Collection.url.

    Proposal

    You said the model is a singleton. In this case I'd suggest to maintain the model and collection separately.

    Since a SomeModel is not accompanied by a certain collection SomeCollection which have a tight relationship it's not necessary to relate them on an attribute level. The effort needed to establish event listeners and sync the data is only at one place.

    // some controller (app main)
    
    var model = new SomeSingletonModel();
    var collection = new SomeSingletonCollection();
    
    var view = new SomeView({
      model: model,
      collection: collection
    });
    

    Probably the resource that is mapped to SomeSingletonModel will deliver an array.

    What are the benefits of using a collection as model attribute (that's what model.get("name") is) over using a plain array? Syncing and change events. Both are probably only necessary when a View updates the Collection's Models. When the View only renders, a Collection does not provide any benefit in many cases.

    If the data of that array needs to be updated, using a Collection is probably the right choice because of Backbone's synching mechanisms.

    But how to keep the collection sync with the model (you ask)?

    Your controller needs to listen to the model and update the collection on sync and reset:

    model.on("sync reset", function() {
      // "priceCollection" is a model attribute 
      collection.reset(model.get("priceCollection"));
    
      // optionally unset "priceCollection" on the model
      this.unset("priceCollection", { silent: true });
    });
    

    This will initialize the collection.

    Any change to the Collection's Models will then only be part of the Collection's or Model's syncing mechanisms.