Labithiotis
Labithiotis

Reputation: 4129

Backbone.js set causes the models already in collection to be "initialize" again

Currently i have a call to server that returns two objects and one of the objects i use to set a collection. (i poll this every 10 seconds, and soon will be using socket.io for this).

I am noticing that my models initialize function is called every time i use set collection with object. I thought the set was smart and only added/changed attr or removed models and for ones unchanged just did nothing.

// All Orders Collection
var AllOrders = Backbone.Collection.extend({
    model: Order,
    url: '/venues/orders'
 });


 var Order = Backbone.DeepModel.extend({
     idAttribute: 'orderid',
     url: '/venues/orders',


    initialize : function(){
        // this is called everytime i use set even if model is in collection
        // do stuff
    }
 })


 *****************
 app.allOrders.set( app.getOrders.get('orders') );

Upvotes: 3

Views: 1252

Answers (2)

Andrew
Andrew

Reputation: 13853

If you look at the backbone source,

When merging models into a collection the _prepareModel method is called before merging which creates a new model from the passed in attributes.

Here is the set code,

 if (!(model = this._prepareModel(attrs = models[i], options))) continue;

    // If a duplicate is found, prevent it from being added and
    // optionally merge it into the existing model.
    if (existing = this.get(model)) {
      if (remove) modelMap[existing.cid] = true;
      if (merge) {
        attrs = attrs === model ? model.attributes : options._attrs;
        existing.set(attrs, options);
        if (sortable && !sort && existing.hasChanged(sortAttr)) sort = true;
      }

So what happens is,

  • A new model is created from your passed in attributes
  • The collection is queried for an existing model with a same id as the new one.
  • If the merge options is true it pushes the new attributes to the existing model.

Upvotes: 2

inf3rno
inf3rno

Reputation: 26129

This depends on how you write your client and services. By default the GET /venues/orders returns the whole order list. If you want to fetch the changes only you have to write your custom sync for the order collection which keeps the current orders, and fetches the changes only from the server (e.g. you send the current ids, or you send the timestamp of the last call). Btw. the initialize will be called by every fetched model because they are created from json and collection.set cannot compare json objects with backbone models, it can only compare backbone models with backbone models.

Possible solutions:

  1. Override set to compare json with backbone models.
  2. Override your app.getOrders.get('orders') & server side code to pull down only the changes, or manually remove the already existing objects from the pullled json.
  3. Move your code from initialize to another place for example to collection.add event handler.

Upvotes: 0

Related Questions