0

I have the following angular2 component, where I implemented a listenerSelectedChanges() on an EventEmitter. I would like to unsubscribe from the events, when needed. For that purpose the idea was - to use a function instead of a lambda.

Now I faced the problem, that in my listenerSelectedChanges() function - the ".this" object becomes invalid.

Question: What is the lifecycle of a function in JS / Typescript? Can the function live longer, than its parent?

export class Auth0Component implements OnInit, OnChanges {

  @Input() selectedEnvironment: Environment;
  @Output() identityTokenReceived = new EventEmitter(); // component should use the emitter of the AWSService

  listenerSelectedChanges = function (idToken: string) {
    this.identityTokenReceived.emit(idToken);
  };


  // bind to the AWSservice emitter
  ngOnChanges(changes: SimpleChanges) {
    console.log(changes);

    if (this.selectedEnvironment !== undefined) {
      // would like to use listenerSelectedChanges() here
      this.selectedEnvironment.auth0Session.identityTokenReceived.subscribe(idToken => {
          this.identityTokenReceived.emit(idToken);
      });
    }

    // unsubscribe here
  }

}
Skip
  • 6,240
  • 11
  • 67
  • 117

3 Answers3

3

Change your implementation to an arrow function to keep the correct this context:

listenerSelectedChanges = (idToken: string) => {
  this.identityTokenReceived.emit(idToken);
};
Poul Kruijt
  • 69,713
  • 12
  • 145
  • 149
  • Would the lambda (arrow function?) be then bound to the live sycle of "this" ? Where is it stated,? Is there any documentation on this? – Skip Mar 04 '19 at 11:48
  • Lambda functions or arrow functions are not have their own "this" scope, so when you use them they take the "this" from their parent scope. Just check my possible duplicate comment to better understanding – Seyhmus Gokcen Mar 04 '19 at 11:58
  • @Skip That's the whole idea of arrow functions. To inherit the scope of the parent. So yes.. same `this`, same everything. Enough documentation about it. More info [here](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Functions/Arrow_functions) – Poul Kruijt Mar 04 '19 at 12:20
  • Then I guess I dont understand, why it is not the same with the function from my `listenerSelectedChanges = function (idToken: string){}` definition. I referenced the `this.identityTokenReceived` in there, and could also reach the variable `identityTokenReceived`. So the `this` seems to be the one of the parent. But the function survived the parent and `this` was suddenly undefined. How to explain that? – Skip Mar 04 '19 at 15:16
  • The function keyword will always create their own this context. What do you mean with 'reach the variable'? – Poul Kruijt Mar 04 '19 at 21:51
  • by "reach the variable" I mean, that I was able to call the emit() method on the classes identityTokenReceived by doing `this.identityTokenReceived.emit()`. Question: if `function()` has an own context, separate from the classes context - does it mean, that the function will be able to live longer than, the class? Or otherway aroung: if a lambda shares a context with the class - does it mean, that it will be disposed together with the class? – Skip Mar 05 '19 at 14:53
  • it will be disposed together with the class, because it's only referenced inside the class. But there is no way of knowing when that will happen, because the garbage collector is relatively random. Either way, that should not be a concern at all. The only issue you were having is that the `this` context was not what you expected it to be. Nothing with life time or disposing – Poul Kruijt Mar 05 '19 at 15:22
2

Define your function like this in order to keep "this" pointing to your component:

 listenerSelectedChanges = (idToken: string) => {
   this.identityTokenReceived.emit(idToken);
 };

And call normally:

this.listenerSelectedChanges()

Hier is the doc of that behavior:

An arrow function does not have its own this. The this value of the enclosing lexical scope is used; arrow functions follow the normal variable lookup rules. So while searching for this which is not present in current scope they end up finding this from its enclosing scope.

Copied from MDN -> Arrow functions

dannybucks
  • 2,217
  • 2
  • 18
  • 24
0

Try to Define a constant named self in the beginning of your method which contain the value of this. Then use it inside, where it's being undefined. Which means your code will be like this:

ngOnChanges(changes: SimpleChanges) {
    const self = this;
    console.log(changes);

    if (this.selectedEnvironment !== undefined) {
      // would like to use listenerSelectedChanges() here
      this.selectedEnvironment.auth0Session.identityTokenReceived.subscribe(idToken => {
          self.identityTokenReceived.emit(idToken);
      });
    }

    // unsubscribe here
}
Seyhmus Gokcen
  • 248
  • 4
  • 10
Mohamad Mousheimish
  • 1,641
  • 3
  • 16
  • 48