Search code examples
angularngrxngrx-store

How to check if state loading AND loaded values are false before calling API in Angular ngrx 8 store?


I am developing functionality where dispatch is not needed if loading or loaded values in state are true. I am facing issues with checking BOTH values in the store before dispatching. Is there a way to combine two selectors before dispatching action?

I need can have two possible forms of a State:

State = {
list: [],
loading: true,
loaded: false
}

or

State = {
list: [],
loading: false,
loaded: true
}

I am trying to do it with two selectors (method in my component):

 checkStore() {
    return this.store.select(getLoading).pipe(
      tap(loading => {
        if (!loading) {
          this.store.select(getLoaded).pipe(
            tap(loaded => {
              if (!loaded) {
                this.store.dispatch(fetchList({ payload: {something} }));
              }
            }),
            take(1)
          );
        } else {
          this.store.dispatch(fetchList({ payload: {something} }));
        }
      }),
      take(1)
    );
  }

And then calling such method in ngOnInit() As i see nothing is being dispatched in this way. Maybe you have suggestions for implementing such functionality?


Solution

  • You can combine two selectors with RxJs' combineLatest. As per its docs

    Combines multiple Observables to create an Observable whose values are calculated from the latest values of each of its input Observables.

    combineLatest([
      this.store.pipe(select(getLoading)),
      this.store.pipe(select(getLoaded)),
    ])
      .pipe(take(1))
      .subscribe(
        ([loading, loaded]: [boolean, boolean]) => {
          if (!loading && !loaded) {
            this.store.dispatch(fetchList({payload: {something}}));
          }
        }
      );
    

    combineLatest returns a new Observable that emits an array with the latest values from the input Observables, so you can deconstruct them [loading, loaded].
    Then you can subscribe to it and check for its values.

    take(1) as you used will get the first value emitted from combineLatest and then completes. Considering your store has an initial state, both selectors will return values on init.