Harry
Harry

Reputation: 3937

concatLatestFrom with multiple selectors ngrx

I am trying to get 2 selectors with the latest concatLatestFrom that was introduced in NgRx 12, however i cant seem to understand what i am doing wrong and i am unable to achieve this.

I have an effect that looks like this

  loadAllCases$ = createEffect(() => this._actions$.pipe(
    concatLatestFrom(() => [
      this.store.pipe(select(CaseSelectors.getAllCases)),
      this.store.pipe(select(CaseSelectors.getCasesLoaded))
    ]),
    navigation(this.caseLandingPage, {
      run: (snap, [loaded, cases]) => {
        if (loaded) {
          return CaseActions.loadAllSuccess();
        } else {
          return this._caseService.getAll().pipe(
            map(cases => CaseActions.loadAllSuccess(cases))
          );
        }
      },
      onError: (action, error) => {
        return CaseActions.loadAllFailed(error);
      }
    })
  ));

However this doesnt seem to work due to type incompatibility

Argument of type 'OperatorFunction<Action, [Action, boolean, Case[]]>' is not assignable to 
parameter of type 'OperatorFunction<Action, ActionOrActionWithState<unknown, Action>>'. 
Type '[Action, boolean, Case[]]' is not assignable to type 'ActionOrActionWithState<unknown,
Action>'.
Type '[Action, boolean, Case[]]' is not assignable to type '[Action, unknown]'.       
Source has 3 element(s) but target allows only 2

However. if i just leave one selector this works fine, is this a case that using concatLatestFrom can only select one selector? Note i have tried chaining them one after the other this produces the same error. Any help or advice appretiated.

Update

This appears to be Nx specific bug, and the navigation pipe it providers, i have oppened a bug related issue with the Nx Repository https://github.com/nrwl/nx/issues/6830

The code in the example works fine if it is piped with any RxJs operation.

Upvotes: 8

Views: 18686

Answers (3)

Michiel
Michiel

Reputation: 4260

I don't think you need the pipe functions, like this:

   concatLatestFrom(() => [
      this.store.select(CaseSelectors.getAllCases),
      this.store.select(CaseSelectors.getCasesLoaded)
    ]),

Upvotes: 1

Anton Kochev
Anton Kochev

Reputation: 370

There is a type declaration for the concatLatestFrom function and its overloaded version

import { Observable, ObservedValueOf, OperatorFunction } from 'rxjs';
export declare function concatLatestFrom<T extends Observable<unknown>[], V>(observablesFactory: (value: V) => [...T]): OperatorFunction<V, [V, ...{
    [i in keyof T]: ObservedValueOf<T[i]>;
}]>;
export declare function concatLatestFrom<T extends Observable<unknown>, V>(observableFactory: (value: V) => T): OperatorFunction<V, [V, ObservedValueOf<T>]>;

https://github.com/ngrx/platform/blob/12.4.0/modules/effects/src/concat_latest_from.ts

So you're right this function accepts either a single observable or an array of observables.

But it seems you're using order of operators in a wrong way

I'm not sure what does navigation and caseLandingPage mean, but this example might give you an idea of how to fix/improve your effect handler

public readonly something$ = createEffect(
    () =>
      this.actions$.pipe(
        ofType(someAction),
        concatLatestFrom(() => [
          this.store.select(selectFoo),
          this.store.select(selectBar),
        ]),
        switchMap(([action, foo, bar]) => {

          // Do what you need

        }),
      ),
  );

Upvotes: 14

timdeschryver
timdeschryver

Reputation: 15505

Hmmmm, the types accept an array of selectors and there's also a test to verify that it works.

Do you have a runnable reproduction? The problem will probably be something else.

The error itself mentions the correct types returned by concatLatestFrom, so my guess would be that the navigate operator needs to be tweaked.

Type '[Action, boolean, Case[]]' is not assignable ...

Upvotes: 1

Related Questions