0

I'm having an issue where I'm attempting to get the value of an error and display a custom error message via a html element. I'm using a Replay Subject to store the error and manage the state of the error in my Interceptor. I'm importing the interceptor correctly into the component and providing it in my module correctly. I'm confused as to why my error doesn't show up when getting an error response from my API.

Here's what I have so far

errorHandlerInterceptor.service.ts

export class ErrorHandlerInterceptor implements HttpInterceptor {

  error: ReplaySubject<string> = new ReplaySubject<string>(1);

  intercept(request: HttpRequest<any>, next: HttpHandler): Observable<HttpEvent<any>> {
    return next.handle(request)
      .pipe(
        retry(1),
        catchError((error: HttpErrorResponse) => {
          let errorMessage = '';
          if (error.error instanceof ErrorEvent) {
            // client-side error
            errorMessage = `Error: ${error.error.message}`;
          } else {
            // server-side error
            errorMessage = `Error Code: ${error.status}`;
          }
          //window.alert(errorMessage);

          this.error.next(errorMessage);

          return throwError(this.error);
        })
      )
  }
}

Then in the html, I async pipe the Replay Subject to only show the error message if the Replay Subject has a value.

component.html

<div
    *ngIf="errorHandlerInterceptor.error | async"
    class="app-alert--error"
  >
    <p class="app-alert__title">
      ERROR
    </p>
    <p id="error-message">
      {{ errorHandlerInterceptor.error | async }}
    </p>
</div>

Any help or suggestions are greatly appreciated!

1 Answer 1

1

Importing the interceptor inside a component does not look like a good pattern to me.

A way to solve this might be to use a service that will propagate the error to its consumers. This way, from my perspective, we can achieve a better separation of concerns.

error.service.ts

@Injectable({
    providedIn: 'root'
})
export class ErrorService {
    private errorStore = new BehaviorSubject(null);
    public error$ = this.errorStore.asObservable();

    emitError (err) {
        this.errorStore.next(err);
    }
}

foo.component.ts

@Component{/* ... */}
export class FooComponent {

    get currentError$ () {
        return this.errorService.error$;
    }

    constructor (private errorService: ErrorService) { }
}

foo.component.html

<!-- ... -->

<div *ngIf="currentError$ | async">
    Error!
</div>

<!-- ... -->

error.interceptor.ts

constructor (private errorService: ErrorService) { }

intercept (/* ... */) {
    return next.handle(req)
        .pipe(
            /* ... */
            catchError(err => {
                /* ... */

                // If error found
                this.errorService.emitError(errorMessage);

                /* ... */
            }),
        )
}
Sign up to request clarification or add additional context in comments.

1 Comment

Awesome, thank you! I ended up finding this article that aligns with your solution. For anyone else that's looking for a similar working solution, check this link out. stackblitz.com/github/melcor76/global-error-handling

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.