During my training, I am in the process of creating a small Angular application. One of the tasks I am working on involves implementing an error interceptor based on the guidelines provided in the Angular tutorial. The main goal is to effectively handle errors and ensure that my components continue to receive data through observables.
This is the code for the Interceptor:
import { Injectable } from '@angular/core';
import {
HttpRequest,
HttpHandler,
HttpEvent,
HttpInterceptor
} from '@angular/common/http';
import { Observable, of } from 'rxjs';
import { catchError } from 'rxjs/operators';
import { ToastrService } from 'ngx-toastr';
@Injectable({
providedIn: 'root'
})
export class ErrorInterceptor implements HttpInterceptor {
constructor(private toastr: ToastrService) { }
private handleError<T> (result?: T) {
return (error: any): Observable<T> => {
// Log the error on the console.
console.log(error);
// Display user friendly message.
this.toastr.error(`${error.error.message}`, `${error.statusText}:`);
// Let the app keep running by returning an empty result.
console.log(result);
return of(result as T);
};
}
intercept(request: HttpRequest<any>, next: HttpHandler): Observable<HttpEvent<any>> {
return next
.handle(request)
.pipe(
catchError(this.handleError<any>({data: {token: 'asd'}}))
);
}
}
This is the code for the Service:
import { Injectable } from '@angular/core';
import { HttpClient } from '@angular/common/http';
import { Router } from '@angular/router';
import { Subscription, Observable, of, throwError } from 'rxjs';
import { tap, map, catchError } from 'rxjs/operators';
import { LoginInput } from '../models/login.input-model';
import { RegisterInput } from '../models/register.input-model';
import { ServerResponse } from '../../../core/models/server-response.model';
import { ToastrService } from 'ngx-toastr';
const root = '/api/';
@Injectable({
providedIn: 'root'
})
export class AuthService {
private loginUrl: string = root + 'auth/login';
private registerUrl: string = root + 'auth/signup';
private login$: Subscription;
private register$: Subscription;
constructor(
private http: HttpClient,
private router: Router,
private toastr: ToastrService) { }
private saveToken(data) {
localStorage.setItem('token', data.token);
}
login(payload: LoginInput): void {
this.login$ = this.http
.post<ServerResponse>(this.loginUrl, payload)
.subscribe((loginData) => {
console.log('loginData: ' + loginData);
// this.router.navigate(['/home']);
});
}
clearLoginSubscription() {
if (this.login$) this.login$.unsubscribe();
}
Desired outcome: The error should be intercepted and returned as an observable. Subscribing to login/register methods should then emit the data. Current issue: The error is intercepted, but no further action takes place. Data is not emitted during login/register subscription.
Note: After experimenting, I found out that moving the handleError function to the service and piping it in a similar way to how it's done in the interceptor produces the desired outcome. However, the same approach does not work when implemented within the interceptor itself.