Yuniku_123
Yuniku_123

Reputation: 279

setTimeout() cannot call nested functions properly

I have a timeout function that looks like this:

setTimeout(this.logout, 1000);

login method:

logout() {
    this.auth_token = "";
    this.loggedIn = false;
    this.emitLogedInStatusChange();
}

isLoggedIn() {
    return this.loggedIn;
}

private emitLogedInStatusChange() {
    this.LoggedInStatusChangedEmitter.emit({
        value: this.loggedIn
    });
}

where event emitter tells main component where the value for loggedIn is changed. The problem is this.emitLogedInStatusChange(); where I got an error message:

this.emitLogedInStatusChange is not a function

My Question is how to properly call this function inside logout so setTimeout could work?

Here is where I call it:

map((res) => { 
 if (res.username === username) { 
   this.auth_token = res.access_token; 
   this.sessionId = res.SessionID;  
   this.loggedIn = true; 
   this.expires = res.expires_in; 
   setTimeout(this.logout, this.expires*1000); 
   this.emitLogedInStatusChange(); 
  }

Upvotes: 1

Views: 2586

Answers (4)

Günter Zöchbauer
Günter Zöchbauer

Reputation: 657446

When passing functions and methods it's always necessary to take care how that affects the scope of this. By default JS uses the scope of the caller.

There are ways to explicitly specify the scope to be used:

setTimeout(this.logout.bind(this), 1000);

but I can't be sure because your code doesn't show where the code is called from.

Alternatively

setTimeout(() => this.logout(), 1000);

can be used but that seems less succinct. For other use cases where parameters are passed to the callback, they need repeated like

someFunction((a, b, c) => this.logout(a, b, c), 1000);

Upvotes: 9

Supamiu
Supamiu

Reputation: 8731

There are two alternatives to solve your problem, the first one (as the other replies suggest) is to bind your method call to this in order to keep context.

setTimeout(this.logout.bind(this), 1000);

The second solution is to declare logout as a variable, this way you don't loose context upon calling it:

logout = () => {
    this.auth_token = ""; 
    this.loggedIn = false;
    this.emitLogedInStatusChange();
}

and then you call it this way:

setTimeout(this.logout, 1000);

Upvotes: 2

Rajesh
Rajesh

Reputation: 24925

setTimeout will add function call to event loop and will fire it from there. So this is lost and set to window(default). You will have to bind this to your function.

setTimeout(this.logout.bind(this), 1000);

Upvotes: 2

Danmoreng
Danmoreng

Reputation: 2367

You are passing the function to the setTimeout().

I would recommend using an anonymous function, which calls the desired function instead:

setTimeout(function(){
    this.logout();
}, 1000);

Upvotes: 0

Related Questions