Backbone: Custom view attributes are shared between different instances

Created on 19 Apr 2012  路  9Comments  路  Source: jashkenas/backbone

Please see this fiddle: http://jsfiddle.net/XgPyH/31/

So we are creating 10 instances of itemView and calling the addItem method to add 10 items to each itemView. Each itemView should have 10 items in their itemArray property. But instead they share the itemArray property and have 100 items in it.

The problem might be that backbone.view is not resetting the custom attributes in the constructor.

question

Most helpful comment

Yes, since itemArray is a property of the itemView prototype, it's shared by all instances of itemView. If you want instances to have their own itemArray you should set it in initialize or in the constructor.

var ItemView = Backbone.View.extend({

  initialize: function() {
    this.itemArray = [];
  },

  ...

});

All 9 comments

Yes, since itemArray is a property of the itemView prototype, it's shared by all instances of itemView. If you want instances to have their own itemArray you should set it in initialize or in the constructor.

var ItemView = Backbone.View.extend({

  initialize: function() {
    this.itemArray = [];
  },

  ...

});

Here's a fiddle that does what you described: http://jsfiddle.net/XgPyH/32/

Hi @braddunbar,

We already used the same solution you posted as a workaround, yet it seems like we shouldn't need to do that. It's quite confusing behavior don't you think?

Can you explain what use having that on the prototype has (I don't quite understand, I'm not saying the current implementation is incorrect - just trying to get some clarification so we can understand).

We often specify all our view's properties in the way that @spawnedc used in his fiddle, as it's then clear what the properties of the view are, if we then have to "override" them in the initialize method as-well that just seems cumbersome.

In the example apps the views properties are specified in the exact same way, (see Todo.js). a "template" variable is specified in the same manner, but of course because it is just an unchanging string we never see this sort of problem.

What is the correct way to specify dynamic view properties, surely it's not the case that we have to override them all in the init method...?

Can you explain what use having that on the prototype has

Putting mutable properties (arrays, hashes, etc.) on the prototype is rarely useful in my experience (though I'm sure there are some instances in which it is).

What is the correct way to specify dynamic view properties, surely it's not the case that we have to override them all in the init method...?

Yes, to set a property with a mutable value on each instance of a class/constructor you should do so in the constructor (or in this case initialize, which is called from the constructor).

As an example, this is how Backbone sets up properties in an instance of Backbone.Model.

@braddunbar If I create a _new_ instance I would expect _all_ the properties will be reset as it's a _brand new_ instance. Isn't this the expected behaviour or am I missing something?

Hi @braddunbar,

Putting mutable properties (arrays, hashes, etc.) on the prototype is rarely useful in my experience (though I'm sure there are some instances in which it is).

Isn't that exactly what Bacbone is doing with itemArray in this case? itemArray is on the prototype which is why the behavior we are experiencing is happening?

I 100% agree with @spawnedc last statement. I wouldn't expect any properties to be shared between instances of "sibling" views.

Actually, none of the properties are reset unless they're reset in the constructor. They're always the same prototype properties shared by all instances created by the same constructor.

var A = function(){};
var a = new A();

var B = function(){};
B.prototype = a;
a.constructor = B;

var b1 = new B();
var b2 = new B();

console.log(b1.foo); // undefined
console.log(b2.foo); // undefined

a.foo = [1];

console.log(b1.foo); // [1]
console.log(b2.foo); // [1]

console.log(b1.foo === b2.foo); // true

If you're interested there's a great explanation here.

Isn't that exactly what Bacbone is doing with itemArray in this case? itemArray is on the prototype which is why the behavior we are experiencing is happening?

Exactly. That's why I recommend creating itemArray in initialize instead of as a prototype property.

@braddunbar Thanks for the explanation and the link - It's still kind of a weird (and unexpected) behavior on one hand, but on the other hand it makes complete sense to share the properties between views.

I'll have a read of the JavaScript Garden article and I'm sure all will become clear :).

Was this page helpful?
0 / 5 - 0 ratings