1

Using the this keyword from within a catch clause after firing a promise reports "this" as being undefined.
What i want to do is simple, i have a Router object injected in the constructor of a service, from a method i fire an http request via a client, in case the response !=2* then i want to redirect the user.
For some reason, the current object (the service), seems gone, it looks like the catch is executed in another thread that is totally unaware of the service: The constructor:

constructor(private router: Router) { }

public sendRequestOrRedirect(){
var url = environment.url
var json = //someJSON here
return this.httpClient.patch(url,json).toPromise().then(res=>{
  return res;
}).catch(err => this.handleErrorResponse(err));

}

private handleErrorResponse (error: Response | any) {
      if(error.status == 401){
        this.router.navigate['/getout'];
        return Promise.reject(error.status);
      }
   }
  }

So the result of this.routerwill eventually throw an error saying that this is actually undefined. Any suggestion about how i could solve this and more importantly, why it happens?

Chris T
  • 8,186
  • 2
  • 29
  • 39
JBoy
  • 5,398
  • 13
  • 61
  • 101

3 Answers3

2

It is all happening because when you do

.catch(this.handleErrorResponse);

Here this has limitations to its scope. It is currently a scope of catch function.

What you need is a lexical scoping

The ES6 arrow function syntax uses “lexical scoping” to figure out what the value of “this” should be. Lexical scoping is fancy way of saying it uses “this” from the surrounding code… the code that contains the code in question.

So when we do

.catch(err => this.handleErrorResponse(err)); //here this points to its module's scope
Manoz
  • 6,507
  • 13
  • 68
  • 114
  • thank you but did not help, i still get: TypeError: Cannot read property 'router' of undefined – JBoy Jun 11 '18 at 13:18
  • @JBoy, is `handleErrorResponse` is a closure function ? as I can see it is a private closure function of `sendRequestOrRedirect`. Is this you did intentionally? – Manoz Jun 12 '18 at 04:41
  • yes, i did this intentionally, i have edited the code as suggested to apply lexical scoping, i was not aware of this, i usually develop in Java which does not have this feature. The problem persists, the function is declared private because this class is the only place where the function should be invoked from. – JBoy Jun 12 '18 at 09:57
  • @JBoy, Now when you edited your question , this now separates private function as to be another function of the class. Are you sure this is not a closure function ? Tell me if its confusing. with the closure I meant a function into function – Manoz Jun 12 '18 at 10:01
  • i was not aware there is a difference between a closure function and a private class-scope function, i created it as separate function because i did not want to create too much spaghetti code in the same place. – JBoy Jun 12 '18 at 10:15
  • 1
    @JBoy, Can you make that function public and see if you get `this` ? However, I don't think this should be a problem though see - https://stackoverflow.com/a/38390379/1982631 – Manoz Jun 12 '18 at 10:36
  • it still does not work when you invoke it as an external function, regardless of its scope, it does work when its an enclosed function `.catch((err) => { if(err.status == 401){ console.log("Got a 401") } });` – JBoy Jun 12 '18 at 11:15
0

Try using this syntax :

.catch(err => this.handleErrorResponse(err));
  • thank you but did not help, i still get: `TypeError: Cannot read property 'router' of undefined` – JBoy Jun 11 '18 at 13:16
  • Your answer is the exact same as mine or @Manoj. I'm guessing you resolved your scoping issue by editing your code, that's all. –  Jun 12 '18 at 11:48
  • no, the function is now defined within the `catch` clause, while before it was a class-member method. thx – JBoy Jun 12 '18 at 12:08
  • According to your issue, it wasn't a class member ... But great if you resolved it. –  Jun 12 '18 at 12:25
0

Fixed it with an inner function:

constructor(private router: Router) { }

    public sendRequestOrRedirect(){
    var url = environment.url
    var json = //someJSON here
    return this.httpClient.patch(url,json).toPromise().then(res=>{
      return res;
    }).catch((err) => {
          if(err.status == 401){
            console.log("Got a 401")
            this.router.navigate(['/getout'])
          }
        });
    }
JBoy
  • 5,398
  • 13
  • 61
  • 101