Error handling in Angular

Error handling in Angular involves capturing and managing errors to ensure a smooth user experience and easier debugging. Angular provides several built-in tools and techniques for handling errors systematically.

1. Handling HTTP Errors

When making HTTP requests, you can handle errors using the HttpClient and the catchError operator from RxJS.

Example

import { Injectable } from '@angular/core';
import { HttpClient, HttpErrorResponse } from '@angular/common/http';
import { catchError, throwError } from 'rxjs';

@Injectable({
  providedIn: 'root',
})
export class DataService {
  private apiUrl = 'https://api.example.com/data';

  constructor(private http: HttpClient) {}

  getData() {
    return this.http.get(this.apiUrl).pipe(
      catchError(this.handleError)
    );
  }

  private handleError(error: HttpErrorResponse) {
    if (error.error instanceof ErrorEvent) {
      // Client-side error
      console.error('Client-side error:', error.error.message);
    } else {
      // Server-side error
      console.error(`Server-side error: ${error.status} - ${error.message}`);
    }
    return throwError(() => new Error('Something went wrong; please try again later.'));
  }
}
  • catchError: Intercepts errors and allows custom handling.
  • throwError: Re-throws the error after handling it for further processing.

2. Global Error Handling

Angular provides a way to handle application-wide errors using the ErrorHandler service.

  • Custom Global Error Handler.
  • Create a custom error handler.
    import { ErrorHandler, Injectable, NgZone } from '@angular/core';
    
    @Injectable()
    export class GlobalErrorHandler implements ErrorHandler {
      constructor(private ngZone: NgZone) {}
    
      handleError(error: any): void {
        // Log the error to the console or a logging service
        console.error('Global Error:', error);
    
        // Notify the user (e.g., using a toast or modal)
        this.ngZone.run(() => {
          alert('An unexpected error occurred.');
        });
      }
    }
    
  • Register the error handler in AppModule.
    import { NgModule } from '@angular/core';
    import { BrowserModule } from '@angular/platform-browser';
    import { AppComponent } from './app.component';
    import { GlobalErrorHandler } from './global-error-handler';
    
    @NgModule({
      declarations: [AppComponent],
      imports: [BrowserModule],
      providers: [{ provide: ErrorHandler, useClass: GlobalErrorHandler }],
      bootstrap: [AppComponent]
    })
    export class AppModule {}
  • The service will be used throughout the entire application to catch logs.

3. Error Interceptors

Use an HTTP interceptor to handle errors globally for all HTTP requests.

Example

  • Create an HTTP interceptor.
    import { Injectable } from '@angular/core';
    import { HttpInterceptor, HttpRequest, HttpHandler, HttpErrorResponse } from '@angular/common/http';
    import { catchError, throwError } from 'rxjs';
    
    @Injectable()
    export class ErrorInterceptor implements HttpInterceptor {
      intercept(req: HttpRequest<any>, next: HttpHandler) {
        return next.handle(req).pipe(
          catchError((error: HttpErrorResponse) => {
            // Handle different error types
            if (error.status === 404) {
              console.error('Not Found:', error.message);
            } else if (error.status === 500) {
              console.error('Server Error:', error.message);
            }
    
            // Optionally, rethrow the error
            return throwError(() => new Error('An error occurred. Please try again later.'));
          })
        );
      }
    }
    
  • Register the interceptor in AppModule.
    import { NgModule } from '@angular/core';
    import { BrowserModule } from '@angular/platform-browser';
    import { HttpClientModule, HTTP_INTERCEPTORS } from '@angular/common/http';
    import { AppComponent } from './app.component';
    import { ErrorInterceptor } from './error-interceptor';
    
    @NgModule({
      declarations: [
        AppComponent
      ],
      imports: [
        BrowserModule,
        HttpClientModule
      ],
      providers: [
        {
          provide: HTTP_INTERCEPTORS,
          useClass: ErrorInterceptor,
          multi: true
        }
      ],
      bootstrap: [
        AppComponent
      ]
    })
    export class AppModule {}
    

4. Using Angular Guards for Route Error Handling

Angular guards can protect routes and handle access-related errors.

import { Injectable } from '@angular/core';
import { CanActivate, Router } from '@angular/router';

@Injectable({
  providedIn: 'root',
})
export class AuthGuard implements CanActivate {
  constructor(private router: Router) {}

  canActivate(): boolean {
    const isAuthenticated = false; // Replace with actual authentication logic
    if (!isAuthenticated) {
      alert('You are not authorized to access this page.');
      this.router.navigate(['/login']);
      return false;
    }
    return true;
  }
}

5. Error Display in the UI

Display user-friendly error messages in the UI using Angular components.

Example

  • Create an error message component.
    import { Component, Input } from '@angular/core';
    
    @Component({
      selector: 'app-error-message',
      template: `
        <div *ngIf="errorMessage" class="error">
          {{ errorMessage }}
        </div>
      `,
      styles: [
        `
          .error {
            color: red;
          }
        `,
      ],
    })
    export class ErrorMessageComponent {
      @Input() errorMessage: string | null = null;
    }
    
  • Use the component.
    <app-error-message [errorMessage]="error"></app-error-message>

6. RxJS Error Handling Strategies

  • Retry Failed Requests.
    import { retry } from 'rxjs';
    
    this.http.get(this.apiUrl).pipe(
      retry(3), // Retry up to 3 times
      catchError(this.handleError)
    );
    
  • Fallback Data.
    this.http.get(this.apiUrl).pipe(
      catchError(() => of([])) // Return fallback data on error
    );

7. Logging Errors

Use external services like Sentry, LogRocket, or custom logging services to log errors.

Example

@Injectable({
  providedIn: 'root'
})
export class LoggingService {
  logError(message: string, stack: string) {
    // Send error logs to an external server
    console.log('Logging error:', message);
  }
}

Summary

  • HTTP Errors: Use catchError to handle API errors.
  • Global Error Handling: Implement a custom ErrorHandler.
  • Interceptors: Handle HTTP errors globally.
  • Guards: Handle access-related errors.
  • Error Messages: Display user-friendly errors in the UI.
  • RxJS: Use operators like retry or catchError for advanced error handling.
  • Logging: Integrate external logging services.

This article will help to understand error handling in different ways and hope it will help in your application.

Up Next
    Ebook Download
    View all
    Learn
    View all