Mark
Mark

Reputation: 1852

Backbone View inheritance sharing properties

I am extending Backbone views like:

var baseView = Backbone.View.extend({
    fruits : [],
    listFruits : function() {
        console.log(this.fruits);
    }
});

var firstView = baseView.extend({
    initialize : function() {
        this.fruits.push("apple");
    }
});

var secondView = baseView.extend({
    initialize : function() {
        this.fruits.push("pear");
    }
});


var firstViewInstance = new firstView(); // ["apple", "pear"]
var secondViewInstance = new secondView(); // ["apple", "pear"]

firstViewInstance.listFruits();
secondViewInstance.listFruits();

To my mind, firstViewInstance and secondViewInstance should be entirely separate, but they are clearly related. How can I achieve two separate view objects, both inheriting from a common base, but not sharing data?

EDIT: Based on answers below I have an updated fiddle at http://jsfiddle.net/qZ7SU/ which seems to solve this problem. I'm still not entirely clear what is going on, but I think explicitly attaching fruits[] to this, creates it as an instance variable, rather than attaching it to the prototype.

Upvotes: 2

Views: 1115

Answers (2)

ehynds
ehynds

Reputation: 4463

I wrote a more detailed blog post about this but the easiest way is to provide a custom constructor that ensures fruits is created on the prototype of each subviews, and not on the baseView.prototype which all subviews inherit.

var baseView = Backbone.View.extend({
  constructor: function() {
    this.fruits = [];
    Backbone.View.apply(this, arguments);
  },
  listFruits : function() {
    console.log(this.fruits);
  }
});

var firstView = baseView.extend({
    initialize : function() {
        this.fruits.push("apple");
    }
});

var secondView = baseView.extend({
    initialize : function() {
        this.fruits.push("pear");
    }
});


var firstViewInstance = new firstView(); // ["apple"]
var secondViewInstance = new secondView(); // ["pear"]

Upvotes: 2

jakee
jakee

Reputation: 18556

This is because the reference to the original fruits-property is the one being copied to the children view. See underscore.js extend

_.extend = function(obj) {
  each(slice.call(arguments, 1), function(source) {
    if (source) {
      for (var prop in source) {
        obj[prop] = source[prop];
      }
    }
  });
  return obj;
};

To inherit from the common base, but not share data, you need to initialize the not-shared properties in the initialize-function.

var baseView = Backbone.View.extend({
  initialize: function() {
    this._initializeBase();
  },

  _initializeBase: function() {
    this.fruits = [];
  },

  listFruits : function() {
    console.log(this.fruits);
  }
});

var firstView = baseView.extend({
  initialize : function() {
    this._initializeBase();
    this.fruits.push("apple");
  }
});

This way the property will be added to the object when it is initialized and the data will not be shared.

Hope this helps!

Upvotes: 4

Related Questions