Reputation: 50362
Is there a way to automatically do an _.bindAll for a backbone.js object?
I was talking to someone a while ago and they said that there was, but I have no idea where to start looking.
Example:
var TheView = Backbone.View.extend({
initialize: function() {
// HOW CAN I AVOID HAVING TO DO THIS?---->
_.bindAll(this,'render','on_element_01_click', 'on_element_02_click');
},
events: {
'click #element_01': 'on_element_01_click',
'click #element_02': 'on_element_02_click',
},
render: function(){
return this;
},
on_element_01_click: function(){
},
on_element_02_click: function(){
}
}
Upvotes: 2
Views: 1081
Reputation: 35790
I've since learned of a easier technique if you want to build bindAll
in to your views (which is handy for things like AJAX callback methods that aren't auto-bound the way event handlers are). Basically you just override the constructor to perform the auto-binding.
var BoundModel = Backbone.Model.extend({
constructor: function() {
Backbone.Model.apply(this, arguments);
if (this.boundMethods) {
_(this).bindAll.apply(this, this.boundMethods);
}
}
})
var SubclassOfBoundModel = Backbone.Model.extend({
boundMethods: ['handleFetchResponse'],
initialize: function () {
this.model.on('sync', this.handleFetchResponse);
}
handleFetchResponse: function() {
// this function is bound to the model instance
}
})
Of course if you just wanted to bind all your methods you could leave out the "boundMethods" part and just have:
constructor: function() {
Backbone.Model.apply(this, arguments);
_(this).bindAll();
}
Upvotes: 2
Reputation: 35790
I tried doing this myself and I was able to get it working with something like this:
function bindOnExtend(clazz) {
var originalExtend = clazz.extend;
clazz.extend = function() {
var newSubClass = originalExtend.apply(this, arguments);
var originalInitialize = newSubClass.prototype.initialize;
newSubClass.prototype.initialize = function() {
// The constructor will get broken by bindAll; preserve it so _super keeps working
var realConstructor = this.constructor;
_.bindAll(this);
this.constructor = realConstructor;
originalInitialize.apply(this, arguments);
};
return bindOnExtend(newSubClass);
};
return clazz;
}
var BoundModel = Backbone.Model.extend();
bindOnExtend(BoundModel);
var BoundView = Backbone.View.extend();
bindOnExtend(BoundView);
However, I wouldn't recommend it. Doing that will make closures for every single method on every single model/view/whatever you instantiate. Not only does that add a slight increase in overall memory usage, it also opens up the possibility of memory leaks if you're not careful. Furthermore, it makes your stacktraces several lines longer, as they have to wind through bindOnExtend.
In my experience, having to do "_.bindAll(this, ...
" is worth the trouble because:
1) it makes my code more clear/obvious to anyone coming after me
2) it encourages me to qualify my bindAll
, instead of just using the 1-arg form
3) I hate wading through long stacktraces
But, if you want it the above code should work.
Upvotes: 1
Reputation: 11317
Do this instead:
_.bindAll(this);
Will bind ALL functions in this view.
Upvotes: 5