public
Last active

Make backbone.js inhertance work for you! (or make view inheritance work in general)

  • Download Gist
gistfile1.js
JavaScript
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64
/**
* Give backbone an easier way to access super properties and methods.
*/
Backbone.View.prototype.parent = Backbone.Model.prototype.parent = Backbone.Collection.prototype.parent = function(attribute, options) {
/**
* Call this inside of the child initialize method. If it's a view, it will extend events also.
* this.parent('inherit', this.options); <- A views params get set to this.options
*/
if(attribute == "inherit") {
this.parent('initialize', options); // passes this.options to the parent initialize method
//extends child events with parent events
if(this.events) { $.extend(this.events, this.parent('events')); this.delegateEvents(); }
return;
}
/**
* Call other parent methods and attributes anywhere else.
* this.parent('parentMethodOrOverriddenMethod', params) <- called anywhere or inside overridden method
* this.parent'parentOrOverriddenAttribute') <- call anywhere
*/
return (_.isFunction(this.constructor.__super__[attribute])) ?
this.constructor.__super__[attribute].apply(this, _.rest(arguments)) :
this.constructor.__super__[attribute];
};
 
var ParentView = Backbone.View.extend({
'anAttribute': "YO!",
 
'events': {
'click .parentSomething': "handleParentSomethingClick"
},
'handleParentSomethingClick': function() {
console.log('parent something was clicked.');
},
 
'parentOnlyFunction': function(arg) {
console.log('a function only in the parent view with arg:', arg);
}
});
 
var ChildView = ParentView.extend({
'initialize': function() {
//inherits events and calls the parent initialize with options
this.parent('inherit', this.options);
//calls parentOnlyFunction and outputs "Hello Parent Only Function" at the end of the console log
this.parent('parentOnlyFunction', "Hello Parent Only Function!");
//logs "YO!"
console.log(this.parent('anAttribute'));
},
 
'events': {
'click .something': "handleSomethingClick"
},
'handleSomethingClick': function() {
console.log('something was clicked.');
}
});

Hi !

I noticed a problem in your implementation regarding Backbone.Model.initialize() method wich takes not only options but attributes too.
I think in your current implementation, you should distinguish this particular case because, for now, calling :
this.parent("inherit", ...)

doesn't allow to initialize Model's attributes given to the constructors as we would do by calling :
initialize: function(attributes, options){
Backbone.Model.prototype.initialize.call(this, attributes, options);
}

By the way, I like your gist because it simplify my life :

  • code is simpler
  • If I change my parent class, I won't have to track every Backbone.XXX.prototype.mymethod.call()

Here's a version that works in the presence of _.bindAll:

Backbone.View.prototype.parent = function (attribute, options) {
  // keep a reference to this
  var self = this;
  /**
   * Call this inside of the child initialization method.
   * It will extend events.
   * this.parent('inherit', this.options); // a views params get set to this.options
   */
  if (attribute == 'inherit') {
    // passes this.options to the parent initialize method
    self.parent('initialize', options);

    // extends child events with parent events
    if (self.events) {
      var parentEvents = self.parent('events');
      $.extend(self.events, parentEvents);
      self.delegateEvents();
    }

    return undefined;
  }

  /**
   * Call other parent methods and attributes anywhere else.
   * this.parent('parentMethodOrOverriddenMethod', params); <- called anywhere or inside overridden method
   * this.parent('parentOrOverriddenAttribute') <- call anywhere
   */
  var value = self.constructor.__super__[attribute];
  if (_.isFunction(value))
    return value.apply(self, _.rest(arguments));
  return value;
};

Sorry, that is not necessary. Just don't do _.bindAll in the parent initialize method. It seems it is only necessary in the child initialize.

Please sign in to comment on this gist.

Something went wrong with that request. Please try again.