Angular NgRx effects, how to pass a parameter?

nperez9 picture nperez9 · Jan 21, 2019 · Viewed 8.7k times · Source

I am trying to send id parameter from the dispatch to the effect, I can't find any example of this case in google.

Here's the code I already have:

The component:

 ngOnInit(): void {
   this.packageClass = `type-${this.package.packageType.toLowerCase()}`;
   // I set the payload to the action
   this.store.dispatch(new LoadClusterInfo({id: this.package.id}));
   this.checkStatus();
 }

The effect (where I need to access the value)

@Effect()
getClusterInfo = 
  this.actions.ofType(resultActions.Type.LOAD_CLUSTER_INFO)
    .pipe(
      switchMap(() => {
        let id = 'HARDCODED_ID';
        return this.service.getPackageCluster(id); // Here is where i need the value
      }),
      map((packageCluster: PackageCluster) => new LoadClusterInfoSuccess(packageCluster)),
      catchError((err: Error) => of(new LoadClusterInfoError(err))),
    );

And last the action:

  export class LoadClusterInfo implements Action {
    readonly type = Type.LOAD_CLUSTER_INFO;
    constructor(readonly payload: any) {}
  }

How can I access the id sent by the component (this.package.id) in the effect?

Answer

timdeschryver picture timdeschryver · Jan 22, 2019

You can access the action's payload property in the switchMap operator. A couple of extra things:

  • Use the pipeable ofType operator because the ofType function is removed in NgRx 7
  • Type the ofType operator to have a typed action
  • use map and catchError on the service stream, otherwise when an error occurs the effect stream will get destroyed. See the NgRx docs for more info.
@Effect()
  getClusterInfo = this.actions
  .pipe(
    ofType<LoadClusterInfo>(resultActions.Type.LOAD_CLUSTER_INFO),
    switchMap((action) => {
      return this.service.getPackageCluster(action.id).pipe(
        map((packageCluster: PackageCluster) => new LoadClusterInfoSuccess(packageCluster)),
        catchError((err: Error) => of(new LoadClusterInfoError(err))),
     ); 
    }),  
  );

Update NgRx v8 +

With createAction and createEffect, the action is automatically inferred so you can do this and benefit from the types:

getClusterInfo = createEffect(() => {
  return this.actions.pipe(
    ofType(loadClusterInfo),
    switchMap((action) => {
      return this.service.getPackageCluster(action.id).pipe(
        map((packageCluster: PackageCluster) => new LoadClusterInfoSuccess(packageCluster)),
        catchError((err: Error) => of(new LoadClusterInfoError(err))),
     ); 
    }),  
  )
}