On one end, I have a stream which may occasionally throw an error:
this.behaviorSubject.error(error)
Later on, however, I want to continue the stream:
this.behaviorSubject.next(anotherValue)
on the other end, I have a subscriber subscribed to behaviorSubject.asObservable()
.
In the subscribtion, I'm handling the value and the error:
.subscribe( ( value ) => { /* ok */ }, ( error ) => { /* some error */ } );
I want the effect to be the same as a simple onSuccess
and onError
callback, where onError
is called every time an error occurs and doesn't prevent future onSuccess
calls from being made. How do I do this with RXJS?
I've looked into catch but it seems to just prevent error from being called on subscribers.
In comparison to a regular Observable, a Subject allows values to be multicasted to many Observers. A Subject and its subscribers have a one-to-many relationship. A Subject can be an Observable as well as an Observer. They hold a registry of many listeners to multiple Observables.
BehaviorSubject is a variant of a Subject which has a notion of the current value that it stores and emits to all new subscriptions. This current value is either the item most recently emitted by the source observable or a seed/default value if none has yet been emitted.
A subject in RxJS is a special hybrid that can act as both an observable and an observer at the same time. This way, data can be pushed into a subject, and the subject's subscribers will, in turn, receive that pushed data.
Short answer: It's not possible.
How to work with this: The basic concept of RxJS is that any error
or complete
-call will basically "kill" a stream. This concept forces you not "just to throw around errors here and there as you please" but to handle errors and the flow of data within your application properly. A BehaviorSubject
for example is typically meant to hold data, however it should not be used to also include the process of retrieving/creating that data and handle possible errors that might occur during the retrieval of the data.
So if you want to go by the book, you should split up your flow into two parts:
As an example your data flow could look as follows (as a rough sketch):
store.ts
dataStore: BehaviorSubject<IData> = new BehaviorSubject<IData>(); errorMessage: BehaviorSubject<IErrorMsg> = new BehaviorSubject<IErrorMsg>();
data-retrieval.ts
fetchDataById(id: string) { httpService.get(`some/rest/endpoint/${id}`) .subscribe(handleData, handleError); } handleData(data: IData) { errorMessage.next(null); dataStore.next(data); } handleError(error: Error) { errorMessage.next(error.message); dataStore.next(null); }
"But this looks like a lot of overhead..." - True, however it ensures a clean and easy-to-understand flow of data within your application, that is easy to test and maintain. Also there are ready-to-use store-concepts like ngrx or redux that could be used.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With