Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Sub Class a Backbone.View Sub Class & retain events

Tags:

I have a generic subclass of Backbone.View which has a close event listener.

var GenericView = Backbone.View.extend({      events : {         "click .close" : "close"     },      close : function () {         console.log("closing view");     }  }); 

I want to subclass this generic class and add some new events. However the below will overwrite the super classes (above) event object. E.g.

var ImplementedView = new GenericView({      // setting this will stop 'close' in Super Class from triggering     events : {         "click .submit" : "submit"     }  });  

How should I create a sub class, in this case ImplementedView and retain the events?

I have found one way to achieve this, by extending the event object when the child class is constructed. However I need to re-trigger this.delegateEvents(), which I am guessing is not good. Can any one comment on this?

var ImplementedView = new GenericView({      initialize : function (options) {          _.extend(this.events, {             "click .submit" : "submit"         });          // re-attach events         this.delegateEvents();     }  }); 
like image 270
Ross Avatar asked Aug 06 '11 17:08

Ross


2 Answers

@Nupul is exactly right: you're not subclassing your GenericView.

In fact, subclassing isn't really the right word here, since JavaScript doesn't do classical inheritance.

So let's first try and understand what's happening here:

var GenericView = Backbone.View.extend( propertiesObj, classPropertiesObj ) 

Backbone.View is a constructor function, that when called with the new keyword, creates a new object for you.

Since this is JS, all function are really function objects, so Backbone.View.extend is just a function hanging off Backbone.View that does a few things:

  1. It sets up the prototype chain, so you can access properties and call functions defined in the 'base' class
  2. It creates and returns a new constructor function you can call (which here would be GenericView) to instantiate objects of your inheriting class
  3. It copies itself to be a function hanging off the constructor function it returns so that you can further inherit.

So the correct way to set up the protoype chain you want is:

var ImplementedView = GenericView.extend({   // implementation goes here }); 

and NOT:

var ImplementedView = new GenericView({//stuff}); 

because this just creates a new instance of a GenericView.

Now, you still have a problem, because when you do something like:

var impl_view = new ImplementedView;  impl_view.events; // This isn't merged with the events you created                   // for the GenericView 

At this point there are different ways to get the result you want, here's one that uses delegateEvents kind of like how you did. Using it isn't bad, incidentally.

var GenericView = Backbone.View.extend({    genericEvents: { 'click .close': 'close' },    close: function() { console.log('closing view...'); }  });  var ImplView = GenericView.extend({    events: { 'click .submit': 'submit' },    initialize: function(options) {     // done like this so that genericEvents don't overwrite any events     // we've defined here (in case they share the same key)     this.events = _.extend({}, this.genericEvents, this.events);     this.delegateEvents()   } }); 
like image 82
satchmorun Avatar answered Sep 27 '22 18:09

satchmorun


Another option is to have a BaseView that overrides the implementation of Extend. Such as:

var BaseView = Backbone.View.extend({         //base view functionality if needed     }); BaseView.extend = function(child){     var view = Backbone.View.extend.apply(this, arguments);     view.prototype.events = _.extend({}, this.prototype.events, child.events);     return view; }; 

This will automatically extend all of your events for anything that inherits from the BaseView.

like image 41
Will Shaver Avatar answered Sep 27 '22 19:09

Will Shaver