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.


Similar Articles