'How to refer to component object within intercept/arrow function?
Here's my code:
export class NetworkInterceptor implements HttpInterceptor {
constructor(private router: Router, private ngZone: NgZone) {}
intercept(request: HttpRequest<unknown>, next: HttpHandler): Observable<HttpEvent<unknown>> {
// ...
return next.handle(request).pipe(
finalize(() => {
// ...
}),
tap({
next(res) {},
error(error) {
if (error instanceof HttpErrorResponse) {
if (error.status === 401) {
this.ngZone.run(() => this.router.navigateByUrl('/account/signin'));
}
}
},
complete() {},
})
);
}
}
But can't use
this.ngZone.run(() => this.router.navigateByUrl('/account/signin'))
within intercept, since this doesn't refers to component's object.
What's the correct way to do this?
Solution 1:[1]
If the intention is to navigate to a route using the router service, on a 401 error, you don't need to use ngZone. ngZone is a service we use when bringing into angular events from the outside of angular's scope/zone.
What you need is to use catchError in a more simplistic way, you will be set for the win with something like the following:
export class NetworkInterceptor implements HttpInterceptor {
constructor(private router: Router) {}
intercept(request: HttpRequest<unknown>, next: HttpHandler): Observable<HttpEvent<unknown>> {
// ...
return next.handle(req).pipe(
catchError((err) => {
if (err instanceof HttpErrorResponse && err.status === 401) {
this.router.navigateByUrl('/account/signin');
}
return throwError(err);
})
);
}
}
Solution 2:[2]
Just use an arrow functino for your tap payload
tap({
next: () => {...},
error: () => {...},
complete: () => {...},
})
EDIT personal opinion, but you should rather use catchError operator, which seems more suited in your case.
Solution 3:[3]
Try declaring a local variable for the router instance inside the intercept function. And then you use that variable in your code.
intercept(request: HttpRequest<unknown>, next: HttpHandler): Observable<HttpEvent<unknown>> {
// ...
const interceptorRouter = this.router;
return next.handle(request).pipe(
finalize(() => {
// ...
}),
tap({
next(res) { },
error(error) {
if (error instanceof HttpErrorResponse) {
if (error.status === 401) {
this.ngZone.run(() => interceptorRouter.navigateByUrl('/account/signin'));
}
}
},
complete() { }
})
);
}
Solution 4:[4]
This is a very simple approach that I had in a past application, I don't know if you find that elegant enough:
@Injectable()
export class AuthInterceptor implements HttpInterceptor {
constructor(private router: Router, @Inject(WINDOW) private window: Window) {}
intercept(request: HttpRequest<any>, next: HttpHandler): Observable<HttpEvent<any>> {
return next.handle(request).pipe(
catchError((error: HttpErrorResponse) => {
if (error?.status === 401) {
logout(this.window, this.router);
}
return throwError(error);
})
);
}
}
You can inject NgZone if the same with Window & Router.
Sources
This article follows the attribution requirements of Stack Overflow and is licensed under CC BY-SA 3.0.
Source: Stack Overflow
| Solution | Source |
|---|---|
| Solution 1 | The Fabio |
| Solution 2 | temp_user |
| Solution 3 | JSantaCL |
| Solution 4 | StPaulis |
