Seth
Seth

Reputation: 984

NgRx Effects and State management

Im trying to work out the folliwing Effect/State scenario and i haven't quite wrapped my head around this.

Ok, so what I'm supposed to do is either load data based upon the standard ID (essentially the identity column in the plan table), OR by a know company identifier.

I have the following

ACTIONS

export class Load implements Action {
  readonly type = PlanActionTypes.Load;

  constructor(public payload: number) {}
}

export class LoadByPropNum implements Action {
  readonly type = PlanActionTypes.LoadByPropNum;

  constructor(public payload: string) { }
}


export class LoadSuccess implements Action {
  readonly type = PlanActionTypes.LoadSuccess;

  constructor(public payload: Plan) {
  }
}

EFFECT:

This Effect Works as intended:

   @Effect()
  loadPlan$: Observable<Action> = this.actions$
    .ofType<Load>(PlanActionTypes.Load).pipe(
      switchMap(action => this.planService.getPlan(action.payload)),
        map((plan: Plan) => {
          return new LoadSuccess(plan);
        }),
      catchError(err => {
        toastr.error(`Could not load plan.`); 
        console.error(err);
        return of(new LoadFail(err));
      })    
    );

This one Does not.

  @Effect()
  loadPlanByProperty$: Observable<Action> = this.actions$
    .ofType<LoadByPropNum>(PlanActionTypes.LoadByPropNum)
    .pipe(
      switchMap(action => this.planService.getPlanByProperty(action.payload)),
      map((plan: Plan) => {return new LoadSuccess(plan);} ),
      catchError(err => {
        toastr.error(`Could not load plan.`);
        console.error(err);
        return of(new LoadFail(err));
      })
);

I understand that what i'm missing is in the reducer/state. So lets take a look at that.

REDUCERS:

 case PlanActionTypes.LoadSuccess: {
         return adapter.addOne(action.payload, {
           ...state,
           selectedPlanId: state.selectedPlanId,
         });
       }

   case PlanActionTypes.Load: {
         return {
           ...state,
           selectedPlanId: action.payload,
         };
       }

STATE:

 export interface State extends EntityState<Plan> {
     selectedPlanId: number | null;
   }

When I use the Load Action, I set the selectedStateId in the reducer. Thus it makes sense why selectedStateid is null for LoadSuccess when I use LoadBypropNum action, but has a value when using the Load action. However, when I call LoadByPropnum - I dont have the ID yet!.

GOAL: I would like to update the architecture such that I have an intermediary step for LoadPlanByProperty$ whereby I update the State SelectedPlanId, once I have retrieved the data. Currently the LoadPlan$ Effect and the LoadPlanByProperty$ Effect retrieve the same record using a different column, and both successfully. I don't want to go get the data, use the id, to go get the same data again.

TL/DR QUESTIONS

  1. How do I link multiple actions together beyond the first switch map?

  2. How do i update the state from one of those additional actions?

Upvotes: 0

Views: 69

Answers (1)

Aragorn
Aragorn

Reputation: 5289

I'm assuming plan:Plan has an id field on it, if so you can assign it from action.payload.<id_field>:

 case PlanActionTypes.LoadSuccess: {
         return adapter.addOne(action.payload, {
           ...state,
           selectedPlanId: action.payload.planId,
         });
       }

Upvotes: 1

Related Questions