I am using a Promise in a controller to get some data via the adapter from the server. The adapter returns the promise and if it is successful I would like to persist it to the store. This may sound a little strange, but this is for a log-in feature and I don’t want to push the user credentials to the store. So, I am basically ending up with something like:
var promise = adapter.send('login', credentials);
promise.then(function(account) {
this.store.push('account', extractedAccount);
}, function(reason) {
// some error handling
});
The problem with that is, that the reference to the controller ‘this’ is no longer available when the promise is fulfilled.
One of the solutions usually seen is to create a local variable called something like ‘that’:
var that = this;
var promise = adapter.send('login', credentials);
promise.then(function(account) {
that.store.push('account', extractedAccount);
}, function(reason) {
// some error handling
});
This works, but I have never really like this approach as it clutters up the code and what has previously naturally been ‘this’ now suddenly is something weird like ‘that’. Is there a cleaner way to keep the context of ‘this’?
This is the standard callback context dilemma. You can use underscore’s bind function, jQuery’s proxy function, or the lexical solution that most people use (var self = this;). I’d also check out Kyle Simpson’s book on “this” and scoping (it’s like 80 pages long, and one of the best JavaScript reads out there).
Personally I use Function.prototype.bind() to create functions bound to this,
promise.then(
function(res) {
this.store.push("x", res);
}.bind(this),
function(err) {
this.error(err);
}.bind(this)
);
… which is far from perfect (and requires a polyfill for older/IE browsers), but I can’t stand variations on the mess that is,
var self = this;
var _this = this;
var that = this;
Using bind() has the advantage of not requiring additional frameworks (outside of polyfills) and (in my opinion) somewhat cleaner and consistent code.
As has already been mentioned, you can use Function.prototype.bind
or assigning this
to another variable to keep it available.
Alternatively you could assign the things you want from this
which I sometimes find nicer to read because the variables have more meaning:
var store = this.store;
var promise = adapter.send('login', credentials);
promise.then(function(account) {
store.push('account', extractedAccount);
}, function(reason) {
// some error handling
});
Another option is coffeescript, but that’s a fairly big hammer for this small nail.
I actually like the idea of just keeping a reference to what I actually need from ‘this’ and name it accordingly. I didn’t know about the bind function, so that’s good to know too.
Thanks about the recommendation for the book. Will have a look at it too.