Ionic version: (check one with "x")
(For Ionic 1.x issues, please use https://github.com/ionic-team/ionic-v1)
[ ] 2.x
[x] 3.x
[ ] 4.x
I'm submitting a ... (check one with "x")
[x] bug report
[ ] feature request
Please do not submit support requests or "How to" questions here. Instead, please use one of these channels: https://forum.ionicframework.com/ or http://ionicworldwide.herokuapp.com/
Current behavior:
this is undefined when running a callback (handler) in the event subscription which is trying to reference another class function. For example, consider the following, a simple class:
import { Events } from 'ionic-angular';
export class MyEventsClass implements OnDestroy {
constructor(private Events events) {
events.subscribe('user:updated', this.saveUser);
}
saveUser() {
// do something with `user`
this.persist();
}
persist() {
// do something to persist
}
ngOnDestroy() {
this.events.unsubscribe('user:updated', this.saveUser);
}
}
When the user:updated handler runs, you receive the error:
Uncaught TypeError: Cannot read property 'persist' of undefined
The handler reference is required when you want to unsubscribe from a particular instance of an event, as you need the same reference to pass in, hence the set up in this manner, and the call in ngOnDestroy. Otherwise, a lambda function would have sufficed.
Expected behavior:
To be able to reference class functions using the this reference.
I have done some debugging, and it is relating to the following line of code:
responses.push(handler(...args));
TypeScript transpiles this to:
responses.push(handler.apply(void 0, args));
And apply's first argument, void 0, results in undefined, hence the above error which makes sense.
Steps to reproduce:
See above.
Related code:
I have opened a StackBlitz to illustrate the issue here: https://stackblitz.com/edit/ionic-fj2swn
There is a workaround to achieve desired functionality, although not quite as nice, which is to curry the function and have saveUsers return a function which you can capture reference to this in via closure:
constructor(private Events events) {
events.subscribe('user:updated', this.saveUser(this));
}
saveUsers(that: any) {
return () => {
that.persist();
}
}
Other information:
Ionic info: (run ionic info from a terminal/cmd prompt and paste output below):
insert the output from ionic info here
So, when consider the following code:
export class HomePage {
constructor(public navCtrl: NavController, public events: Events ) { }
ngOnInit() {
this.events.subscribe('user:updated', this.saveUser )
}
saveUser() {
// do something with `user`
this.persist();
}
persist() {
// do something to persist
console.log('on persist');
}
when this code is compiled to javascript it becomes on:
```
HomePage.prototype.ngOnInit = function () {
this.events.subscribe('user:updated', this.fun);
};
HomePage.prototype.saveUser = function () {
this.persist();
};
HomePage.prototype.persist = function () {
console.log('on persist');
};
HomePage.prototype.editUser = function () {
this.events.publish('user:updated', { edited: true });
};
so `this` on `saveUser` refer to function `saveUser` and not the class HomePage. So the error.
To solve this you have two choices:
first use arrow functions:
```...
ngOnInit() {
this.events.subscribe('user:updated', () => {
this.saveUser();
})
}
...
or
...
fun: any;
ngOnInit() {
this.fun = this.saveUser.bind( this );
this.events.subscribe('user:updated', this.fun )
}
...
I hope I have helped.
Thanks for the issue! This issue is being closed due to inactivity. If this is still an issue with the latest version of Ionic, please create a new issue and ensure the template is fully filled out.
Thank you for using Ionic!
Most helpful comment
So, when consider the following code:
when this code is compiled to javascript it becomes on:
```
HomePage.prototype.ngOnInit = function () {
this.events.subscribe('user:updated', this.fun);
};
HomePage.prototype.saveUser = function () {
this.persist();
};
HomePage.prototype.persist = function () {
console.log('on persist');
};
HomePage.prototype.editUser = function () {
this.events.publish('user:updated', { edited: true });
};
or
I hope I have helped.