Search code examples
rxjsngrx

NGRX concat two action


I am using NGRX and Angular 11. I am trying to, when an action is executed, call another action, listen to the success of it, and if it succeeded dispatch a final action:

Here my code a bit simplified :

@Effect()
  getUserSettingSuccess$ = this.actions$.pipe(
    // When this action `GetUserSettingsSuccess` is executed
    ofType<featureActions.GetUserSettingsSuccess>(featureActions.ActionTypes.GetUserSettingsSuccess),
    concatMap((action) =>
      of(action).pipe(withLatestFrom(this.store$.pipe(select(ProjectsStoreSelectors.selectedProjectId))))
    ),
    // I want to dispatch a new action 
    tap(([action, projectId]) => new ModelsStoreAction.GetAllModelsRequest({ projectId })),
    // and listen to the success / failure of that action. 
    // If success dispatch `SetModelSelection` else do nothing.
    map(([action]) =>
      this.actions$.pipe(
        ofType(ModelsStoreAction.ActionTypes.GetAllModelsSuccess),
        takeUntil(this.actions$.pipe(ofType(ModelsStoreAction.ActionTypes.GetAllCesiumModelsFailed))),
        first(),
        map(() => new ModelsStoreAction.SetModelSelection())
      )
    )

The problem I have is that, the above code do not dispatch a valid action. But I am getting a bit lost with all those rxjs operator.


Solution

  • Here would be my approach:

    @Effect()
      getUserSettingSuccess$ = this.actions$.pipe(
        // When this action `GetUserSettingsSuccess` is executed
        ofType<featureActions.GetUserSettingsSuccess>(featureActions.ActionTypes.GetUserSettingsSuccess),
        
        concatMap((action) =>
          of(action).pipe(withLatestFrom(this.store$.pipe(select(ProjectsStoreSelectors.selectedProjectId))))
        ),
    
        // I want to dispatch a new action 
        tap(([action, projectId]) => new ModelsStoreAction.GetAllModelsRequest({ projectId })),
        
        // and listen to the success / failure of that action. 
        // If success dispatch `SetModelSelection` else do nothing.
        switchMap(
          ([action]) => this.actions$.pipe(
            // adding all the possibilities here
            ofType(ModelsStoreAction.ActionTypes.GetAllModelsSuccess, ModelsStoreAction.ActionTypes.GetAllCesiumModelsFailed),
    
            first(),
            filter(a => a.type === ModelsStoreAction.ActionTypes.GetAllModelsSuccess.type),
            map(() => new ModelsStoreAction.SetModelSelection()),
          )
        )
      )
    

    It didn't work before because this.actions$ is essentially a type of Subject and an effect is not expected to return an Observable-like value. In order to solve that, I used switchMap, which will handle the inner subscription automatically.