Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Angular 2 Ngrx Store, Effects and "Ephemeral States"

Tags:

angular

ngrx

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...

like image 314
Brett Avatar asked Oct 06 '16 00:10

Brett


People also ask

Where is NgRx store data is stored?

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.

What is a good use case for NgRx store?

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.

Is Redux better than NgRx?

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.

What is effects in NgRx Angular?

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.


1 Answers

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:

  • https://github.com/ReactiveX/RxJS/issues/1135
  • https://github.com/ReactiveX/rxjs/issues/1420
  • https://egghead.io/courses/rxjs-subjects-and-multicasting-operators
like image 189
Brett Avatar answered Oct 14 '22 05:10

Brett