Reputation: 2235
I'm having an issue with Typescript in which the this
key word is showing up as undefined when debugging and, therefore, not calling some of my private class methods which are called from a callback method. My text editor seems to think that my reference is fine and is giving me intellensense, so I would assume the code is ok. below is a shortened example. The cacheUser
and _processSuccessfulRegistration
are not getting hit when the _handleCreationResponse
callback method is called.
export class User extends Observable {
public email: string;
public password: string;
public username: string
constructor() {
super()
this.email = '';
this.password = '';
this.username = '';
}
public register() {
let user = {
// build out object
}
userService.createAccount(user)
.catch(/* handle error */)
.then(this._handleCreationResponse)
}
private _handleCreationResponse(response) {
let status = response.status;
let userData = response.result;
switch (status) {
case ApiStatus.Success:
this._cacheUser(userData);
this._processSuccessfulRegistration(userData);
break;
case ApiStatus.SomeError:
// handle errors
break;
default:
// do something else
break;
}
}
private _cacheUser(user) {
// handle user caching
}
private _processSuccessfulRegistration() {
// call some other services and
// navigate to a new view
}
}
Upvotes: 4
Views: 3402
Reputation: 164307
When you pass functions as callbacks the functions are not bound to a specific this
, so when they get executed this
will refer to something else.
To avoid that you can either bind the function:
userService.createAccount(user)
.catch(/* handle error */)
.then(this._handleCreationResponse.bind(this)
Or use an arrow function which do save the right context for this:
userService.createAccount(user)
.catch(/* handle error */)
.then(response => this._handleCreationResponse(response))
There's another option which is to create this method as an arrow function to begin with:
private _handleCreationResponse = (response) => {
let status = response.status;
let userData = response.result;
switch (status) {
case ApiStatus.Success:
this._cacheUser(userData);
this._processSuccessfulRegistration(userData);
break;
case ApiStatus.SomeError:
// handle errors
break;
default:
// do something else
break;
}
}
Then you can pass it as you did before and the context of this
will be preserved.
If you use this option be aware that it's a bit different than what you had before as _handleCreationResponse
won't be a method anymore but a function property of the instance (that is, it won't be part of the prototype).
Here's a short example to show the difference:
class MyClass {
method1() {
console.log("method 1");
}
method2 = () => {
console.log("method 2");
}
}
Compiles to:
var MyClass = (function () {
function MyClass() {
this.method2 = function () {
console.log("method 2");
};
}
MyClass.prototype.method1 = function () {
console.log("method 1");
};
return MyClass;
}());
You cannot override methods which are arrow functions in extending classes, but as your method is private it shouldn't be a problem..
Upvotes: 5