Chris Dutrow
Chris Dutrow

Reputation: 50362

Automatic _.bindAll() in backbone.js

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

Answers (3)

machineghost
machineghost

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

machineghost
machineghost

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

Poni
Poni

Reputation: 11317

Do this instead:

_.bindAll(this);

Will bind ALL functions in this view.

Upvotes: 5

Related Questions