Uri
Uri

Reputation: 2257

Setting "this" to the instance, in a callback set during the creation of a prototype function

I have this code:

var createAllAreSelectedClickedHandler = function(selectablesArrayGetter) {
    return function() {
        var array = selectablesArrayGetter();
        var desiredState = array.every(function(selectable) { return selectable.selected; }) ? false : true;
        array.forEach(function(selectable) {
            selectable.selected = desiredState;
        });
    };
};

Followed by this one:

function PromoViewModel() { this.registrations = [...] }   

PromoViewModel.prototype.allEventsSelectedClickedHandler = createAllAreSelectedClickedHandler(function() { return this.registrations; }));

I can't manage to set the correct value of this. The "this" value when the function is created points to Window so I can't do .bind(this). I've tried doing .bind(PromoViewModel.prototype) but it lacks all the precious instance fields set inside the constructor.

I know I could simply set this.allEventsSelectedClickedHandler in the constructor function, but I'm trying to separate the methods creation from the variables.

Upvotes: 2

Views: 79

Answers (4)

Patrick Racicot
Patrick Racicot

Reputation: 79

Ok here is what I did.

In the prototype definition instead of directly associating it to createAllAreSelectedClickedHandler function, I actually define a function that returns the createAllAreSelectedClickedHandler function. By doing this, I can define a variable (in this case protoScope) that maps this context when defined. When doing that, if you put a break-point in the createAllAreSelectedClickedHandler function you will see that the selectablesArrayGetter value is correct (the acutal registrations array).

PromoViewModel.prototype.allEventsSelectedClickedHandler = function (){
    var protoScope = this;
    return createAllAreSelectedClickedHandler(function() { 
        return protoScope.registrations; 
    });
}

Upvotes: 0

Micha Schwab
Micha Schwab

Reputation: 798

the function that you're passing as callback uses this, but doesn't have the PromoViewModel context. You can ensure the method has the proper context by binding this to a variable.

function PromoViewModel()
{
    var me = this;
    this.registrations = [...];
    this.allEventsSelectedClickedHandler = createAllAreSelectedClickedHandler(function() {
        return me.registrations;
    });
}  

Working fiddle: http://jsfiddle.net/michaschwab/coegnL5j/9/ also has Bergi's answer in there (commented out) to show that that works just as well.

Upvotes: 0

leo.fcx
leo.fcx

Reputation: 6467

I'd recommend defining your PromoViewModel.prototype.allEventsSelectedClickedHandler method as follows:

PromoViewModel.prototype.allEventsSelectedClickedHandler = function() {
    var _array = this.registrations;
    var desiredState = _array.every(function(selectable) { return selectable.selected; }) ? false : true;
    _array.forEach(function(selectable) {
        selectable.selected = desiredState;
    });
};

Upvotes: 0

Bergi
Bergi

Reputation: 664548

The problem is the call selectablesArrayGetter(); which determines the this value for the callback.

You will need to "pass" the this value that the method (i.e. the closure you are returning) is invoked on, using call:

var array = selectablesArrayGetter.call(this);

Upvotes: 1

Related Questions