7

I want to have a generic way of handling exceptions, expecially 401's received from the backend. When I don't extract the catchError content, it works fine. However if I simply extract it to a specific function, then nothing gets injected in that function:

return this.http.request<T>(new HttpRequest('POST', this.appConfig.baseApiPath + url, file, {
            reportProgress: true,
            headers: headers,
            params: urlParams
        })).pipe(
            catchError((err) => {
                if (err.status === 401) {
                    this.router.navigateByUrl('/login?expired=true');
                }
                return Observable.throw(err || 'Server error')
            })
        );

This works! However I wanted to handle this redirect code in a function in order to reuse it by other methods.

Here I exported that into a function:

    return this.http.request<T>(new HttpRequest('POST', this.appConfig.baseApiPath + url, file, {
        reportProgress: true,
        headers: headers,
        params: urlParams
    })).pipe(
        catchError(this.handleHttpError),
    );

handleHttpError(error: HttpErrorResponse) {
    if (error.status === 401) {
        this.router.navigateByUrl('/login?expired=true'); --> router is null!
    }
    return Observable.throw(error || 'Server error')
}

And that's where router (as well as other constructor injected services) are null if I use that way of working... could you suggest why?

mruanova
  • 6,351
  • 6
  • 37
  • 55
Qualaelay
  • 713
  • 2
  • 10
  • 21
  • 1. you did not post the full code, especially the part you have your router declared 2. why don't you just use [interceptor](https://angular.io/guide/http#intercepting-requests-and-responses) instead? – smnbbrv Aug 25 '18 at 19:44
  • Possible duplicate of [How to access the correct \`this\` inside a callback?](https://stackoverflow.com/questions/20279484/how-to-access-the-correct-this-inside-a-callback) – Matt McCutchen Aug 25 '18 at 19:45

2 Answers2

12

The reason is that you're losing context. When function is declared in such way this keyword is about scope of the function, not the whole class. Not to lose context you shoud use an arrow function:

handleHttpError = (error: HttpErrorResponse) => {
    if (error.status === 401) {
        this.router.navigateByUrl('/login?expired=true');
    }
    return Observable.throw(error || 'Server error')
}
dsych
  • 754
  • 7
  • 13
8

a better approach is to bind 'this' to your call:

catchError(this.handleHttpError.bind(this))
Avi
  • 1,924
  • 3
  • 17
  • 31