Handling errors in NGXS (angular) with global error handler
Asked Answered
B

2

7

I'd like to handle errors in NGXS in two ways. The first way is handling an error on the store dispatch in a component. The second way is a global angular error handler as a fallback for when the error is unhandled (not handled by first way).

But the problem is that the global error handler is always called by NGRX when there is an error in an action handler.

So given this code in the component:

this.store.dispatch(new FetchAction())
   .subscribe( error: () => console.log('fetch error occured'))

this action handler:

fetch() {
   return this.http.get('..');
}

and this global error handler:

export class GlobalErrorHandler extends ErrorHandler {
   handleError(err: any) {
      console.log('unexpected error occured');
   }
}

There would be two error messages in the console. One from the subscribe of the dispatch and one from the global error handler because there was an error in the action handler.

Now I could catch errors in the action handler but that would be the wrong place to do so because the action handler shouldn't know that an error from this action is handled in a component.

I made a stackblitz which shows two errors in the console when clicking the button: https://stackblitz.com/edit/ngxs-error-throw-r42fkb?file=src/app/app.component.ts

Blackett answered 3/7, 2019 at 14:41 Comment(4)
Hi, I recommend you to learn about Angular Interceptors: scotch.io/@vigneshsithirai/…Lamdin
I do know about http interceptors but it's not a solution for this. A http interceptor still has to return a result. You can't obviously catch an error there and tell the app the response was a success and return it some value (what would that even be?) when indeed it wasn't successful at all. It only works when having no global error handler. But having a global error handler should be supported all the way because it's an integral part of angularBlackett
Created a new stackblitz with reproduction of that issue: stackblitz.com/edit/… Hope somebody will help.Bloodmobile
Did you manage to find a solution to this one? I have the same problem.Diligence
J
1

Use RxJS catchError operator to handle errors at low level:

This way, you caught the error so it won't call your global action handler.

this.store.dispatch(new FetchAction())
   .pipe(catchError(error => /* Do something specific with the error. */))
   .subscribe(() => { /* Do something with the success result. */ })

Let the error bubble up to the global action handler:

Nothing special here. Just ignore the error. Do this when you don't know what to do with the error.

this.store.dispatch(new FetchAction())
   .subscribe(() => { /* Do something with the success result. */ })

You can re-throw a more specific error if you want with throwError so you have more information when you will handle it at a higher level.

this.store.dispatch(new FetchAction())
   .pipe(catchError(error => throwError(new Error('Some specific error.'))))
   .subscribe(() => { /* Do something with the success result. */ })
Jarib answered 19/11, 2019 at 13:40 Comment(3)
"This way, you caught the error so it won't call your global action handler." I guess you mean global error handler. But that is exactly the point. This will STILL call the global error handler when there is an error in an ngxs action handler. If you don't have the catchError and just subscribe the global error handler will actually be called twice.Blackett
I don't know what is causing this, maybe you can use a Subject type piped with distinctUntilChanged or debounceTime inside your custom global error handler to ignore duplicates.Conservatoire
Yes, that's what I'm using but obviously this is not ideal. Also it does not solve the problem. When I dispatch an action, subscribe to it and use catchError I'd think I'd be able to explicitly handle this error. But the global error handler is still called. So it's not possible to have the global error handler as a fallback that is only called when I don't handle errors on dispatchBlackett
I
0

I have the same problem. But as the documentation says it is by design. Error is beging propagated to main ErrorHandler despite you do handle on the upper level.

If an unhandled exception is thrown inside an action, the error will be propagated to the ErrorHandler and you can also catch it subscribing to the dispatch Observable. If you subscribe to the dispatch Observable the error will be caught twice, once in the ErrorHandler and on your dispatch handle

Interrogation answered 19/2, 2020 at 11:12 Comment(0)

© 2022 - 2024 — McMap. All rights reserved.