Working in the context of a form component:
I am trying to show the states of the form to the user "pending, success, error, pristine". I don't want to have those states in the store as they are "ephemeral states".
I have an Effect:
@Effect()
addTagToVideoEffect_ = this.appState_
.ofType(TagActions.ADD_TAG_TO_VIDEO)
.map<AddTagToVideo>(action => action.payload)
.switchMap((addTag: AddTagToVideo) => this.dtsiVideosService.addTagToVideo(addTag)
.map((addTag: AddTagToVideo) => TagReducers.addTagToVideoComplete(addTag))
.catch((err) =>Observable.throw(err))
);
and in my form component I am dispatching the TagActions.ADD_TAG_TO_VIDEO
and subscribing to it:
onTag(tag: TagEntity) {
this.subscription = this.tagActions.addTagToVideoEffect_.subscribe(
this.onAddTagSuccess,
this.onAddTagError
);
this.tagActions.addTagToVideo({videoId: this.videoId, tag: tag});
}
the .tagActions.addTagToVideoEffect_.subscribe
results in having my effect called twice. How can we get the results of the effects in the view without passing by the store for all those ephemeral states ? And not having the effect called twice...
Where Does NgRx Store Data? NgRx stores the application state in an RxJS observable inside an Angular service called Store. At the same time, this service implements the Observable interface. So, when you subscribe to the store, the service actually forwards the subscription to the underlying observable.
NgRx is a global state management library that helps decouple the Domain and Business layers from the Rendering layer. It's fully reactive. All changes can be listened to using simple Observables, which makes complex business scenarios easier to handle.
NgRx, which is the Angular version of Redux for React is for State Management. In React, state management can get complicated, and Redux is there to help. For Angular, this should not be the case as everything is synced due to two way data binding.
NgRx Effects are a popular part of NgRx, a state management library built for Angular. Effects are usually used to perform side effects like fetching data using HTTP, WebSockets, writing to browser storage, and more.
The reason why you get the effect call twice is because its only an Observable. You need to turn it into a Publisher.
@Effect()
addTagToVideoEffect_ = this.appState_
.ofType(TagActions.ADD_TAG_TO_VIDEO)
.map<AddTagToVideo>(action => action.payload)
.switchMap((addTag: AddTagToVideo) => this.dtsiVideosService.addTagToVideo(addTag)
.map((addTag: AddTagToVideo) => TagReducers.addTagToVideoComplete(addTag))
.catch((err) => Observable.throw(err))))
.share();
Then you can work with it in your view:
tagFormState_: BehaviorSubject<FormState> = new BehaviorSubject<FormState>({});
onTag(tag: TagEntity) {
Observable.from(this.tagActions2.addTagToVideoEffect_)
.first()
.toPromise()
.then(this.onAddTagSuccess, this.onAddTagError)
this.tagFormState_.next({pending: true});
this.tagActions.addTagToVideo({videoId: this.videoId, tag: tag});
}
onAddTagSuccess = (payload) => {
this.tagFormState_.next({success: 'Success !'});
this.resetTagFormState();
}
onAddTagError = (err) => {
this.tagFormState_.next({error: err.message});
this.resetTagFormState();
}
resetTagFormState() {
setTimeout(_=> {
this.tagFormState_.next({});
}, 1000);
}
Resources on the subject that helped me sort this out:
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