Using angular snack bar to handle errors, but I already handeled errors in its interceptor

157 views Asked by At

I wanna use snack bar to show users the error, I want to know if I have to use error in my subscription method to use snack bar? is there any way to not use error in subscribe method and show error with snack bar? here's my http error-catching interceptor:

export const httpErrorInterceptor: HttpInterceptorFn = (req, next) => {
  return next(req).pipe(
    catchError((error: HttpErrorResponse) => {
      return throwError(() => error);
    })
  );
};

and here is my subscribe method that subcribes and emit value from service:

  login(): void {
    let userInput: UserLogin = {
      email: this.EmailCtrl.value,
      password: this.PasswordCtrl.value
    }

    this.accountService.login(userInput).subscribe({
      next: () => {
        this.router.navigateByUrl('/');

        this.snackBar.open('Login Successful', 'Close', {
          duration: 3000
        });
      },
      error: () => {
        this.snackBar.open('Login Failed', 'Close', {
          duration: 3000
        });
      }
    });
  }

is there a way to use snack bar for errors and don't use error in login method?

2

There are 2 answers

0
John On

Your HTTP interceptor is a no-op. All it does is catch and rethrow the same exception without any side effects. You could remove it with no changes to your application.

To achieve your goal, you could define a global error handler using ErrorHandler.

You can name this file src/app/global-error-handler.ts.

import { ErrorHandler, Injectable, NgZone } from "@angular/core";
import { MatSnackBar } from "@angular/material/snack-bar";

@Injectable({
  providedIn: 'root'
})
export class GlobalErrorHandler implements ErrorHandler {
  constructor(
    private _snackBar: MatSnackBar,
    private _zone: NgZone,
  ) { }

  handleError(error: any): void {
    this._zone.run(() => {
      this._snackBar.open(error, 'Close', { duration: 3000 });
    });
  }
}

Note that NgZone is used to fix a positioning issue with MatSnackBar.

You will also need to add a provider:

{ provide: ErrorHandler, useClass: GlobalErrorHandler }

For standalone applications, you can add it in src/app/app.config.ts:

export const appConfig: ApplicationConfig = {
  providers: [
    { provide: ErrorHandler, useClass: GlobalErrorHandler }
  ]
};

Otherwise add it in the root module:

@NgModule({
    // ...
    providers: [
        { provide: ErrorHandler, useClass: GlobalErrorHandler },
    ]
})
export class AppModule { }
0
The Fabio On

you can call the snackbar service from your interceptor and send it as a parameter for your error handler. Then you interpret the error object as you need and can display a snackbar msg.

Something like this should be enough:

@Injectable()
export class YourInterceptor implements HttpInterceptor {

  constructor(private snackBar: MatSnackBar) {
    ...
  }


  intercept(req: HttpRequest<any>, next: HttpHandler): Observable<HttpEvent<any>> {
  ...
    return httpErrorInterceptor(req, next, this.snackBar)  
  }
...
}

export const httpErrorInterceptor: HttpInterceptorFn = (req, next, snackBar) => {
  return next(req).pipe(
    catchError((error: HttpErrorResponse) => {
        if (err instanceof HttpErrorResponse) {
          const errorMessage = getYourMessage(err) // <-- you define how to interpret the error here
          snackBar.open(errorMessage, 'Close', {
            duration: 3000
          });
        }
      
      return throwError(() => error);
    })
  );
};