Search code examples
javascriptangulartypescriptngrxngrx-effects

Getting error Effect "n.loadInfo$" dispatched an invalid action


I am trying to write an effect for an action but it is throwing an error as: "Effect "n.loadInfo$" dispatched an invalid action: null Error"

I have my effect as below:

  @Effect()
  loadInfo$ = 
        this.actions.ofType(fromHeaderActions.EInfoActions.OPEN_INFO).pipe(
    withLatestFrom(
      this.store.select(fromSelectors.GetINFOPayload)),
    switchMap(([action, infoPayLoad]) => {
      let cAction: fromHeaderActions.OpenINFOWIdget = 
          <fromHeaderActions.OpenINFOWIdget>action;
      return this.infoService.loadINFO(infoPayLoad).pipe(
       // Dispatch success action
          map(response => new 
              fromHeaderActions.OpenINFOWIdgetSuccess(response)),
      catchError(error => {
        return of(new 
         fromHeaderActions.OpenINFOWIdgetFail(error.message))
      })
     )
   })
 );

I have my action defined as below:

export class OpenINFOWIdget extends BaseGetDetailsAction implements Action {
  readonly type = EInfoActions.OPEN_INFO; 
  constructor() {
  super();   
 }
}


//added action after the comment
export class OpenINFOWIdgetSuccess extends BaseGetDetailsAction 
 implements Action {
 readonly type = EInfoHeaderActions.OPEN_INFO_SUCCESS;
 constructor(public payload: INFO) {
  super();
  }
 }

export class OpenINFOWIdget extends BaseGetDetailsAction implements Action {
  readonly type = EInfoActions.OPEN_INFO_FAIL;
  constructor(public payload: string) {
  super();    
 }
}

And in the service as below:

public INFOPayloadsource = new BehaviorSubject<INFO>(initINFO);
infoPayload$ = this.INFOPayloadsource.asObservable();

private SelectedInfoSource = new Subject<INFO>();
selectedInfo$ = this.SelectedInfoSource.asObservable();

  loadINFO(payload: INFO): Observable<INFO> {    
   if (payload != null) {
     this.IsInfoEnableSource.next(true);     
     this.InfoPayloadsource.next(payload);
   }
   return this.selectedInfo$;
  }

I have selector as below that is used in the effect:

export const GetINFOPayload = createSelector(getInfoState, 
(state: 
      InfoDetailsState) => {
        if (state) {
          if (state.infoDetails != null && 
              state.infoDetails.INFODetail != 
              null &&
              state.infoDetails.INFODetail.Active != null) {
           let payload: INFO = { ...initINFO };
           payload = state.infoDetails.INFODetail.Active;
           return payload;
        }
      }
    return null;
  });

Create reducer as below after the comment:

case 
  fromInfoDetailsHeaderActions.EInfoHeaderActions.OPEN_INFO: {
      return {
        ...state,
        IsScreenOverlay: true,
        IsEditable: false
      }
    };
    case fromInfoDetailsHeaderActions.EInfoHeaderActions.OPEN_INFO_SUCCESS: {
      return {
        ...state,
        IsScreenOverlay: false,
        IsEditable: true
      }
    };

I would really appreciate if anyone can help on it. Thank you!


Solution

  • Your effect is trying to dispatch the result of this.infoService.loadINFO(), which is why you get the error saying that it is not a valid action.

    You should map this to a success action instead:

      @Effect()
      loadInfo$ = this.actions.ofType(fromHeaderActions.EInfoActions.OPEN_INFO).pipe(
        withLatestFrom(
          this.store.select(fromSelectors.GetINFOPayload)
        ),
        switchMap(([action, infoPayLoad]) => {
          let cAction: fromHeaderActions.OpenINFOWIdget = <fromHeaderActions.OpenINFOWIdget>action;
    
          return this.infoService.loadINFO(infoPayLoad).pipe(
            // Dispatch success action
            map(response => new fromHeaderActions.OpenINFOWIdgetSuccess(response)),
            catchError(error => {
              return of(new fromHeaderActions.OpenINFOWIdgetFail(error.message))
            })
           )
         })
     );
    

    You will also need to add the corresponding action and handle it in your reducer, if necessary.