Search code examples
angularngrxngrx-effects

NgRx effect executed only once


I have a modal window clicked that when the Add user button is clicked it adds the value in the textbox, after it does some internal calls like checking the validity of the value in the textbox. The http calls are executed in an effect, which gets called only for the first entry.

enter image description here

The problem is that the effect that does the back-end call is executed only once.

The template of the modal:

<button class="close" mat-button (click)="closeDialog()">x</button>
<h1 mat-dialog-title>Share with other users</h1>
<div mat-dialog-content>
  <ng-container *ngFor="let principal of data.productList.sharedWith; trackBy: sharedPrincipalsTrackFunction">
    <p>{{principal.uid}} <button (click)="removeUserFromSharedProductList(data.productList.name, principal.uid)">x</button></p>
  </ng-container>
  <mat-form-field>
    <mat-label>Share with other users</mat-label>
    <input matInput [(ngModel)]="data.userId">
  </mat-form-field>
</div>
<div mat-dialog-actions>
  <button class="btn btn-primary" mat-button (click)="addUserToProductList(data.productList.name, data.userId)" [disabled]="!data.userId">Add user</button>
</div>

Typescript code of the component:

  addUserToProductList(productListName: string, userId: string) {
    this.productListService.shareProductList(productListName, userId);
    this.updateDialogData(userId);
  }

productListService.shareProductList:

  shareProductList(productListName: string, userId: string) {
    this._store.dispatch(
      ProductListActions.shareProductListWithUser({
        productListName: productListName,
        userId: userId
      })
    );
  }

effect:

  shareProductListWithUser$ = createEffect(() =>
    this._actions$.pipe(
      ofType(ProductListActions.shareProductListWithUser),
      mergeMap(action =>
        forkJoin(
          of(action.productListName),
          this._productListOccService.shareProductListWithUser(
            action.productListName,
            action.userId
          )
        )
      ),
      switchMap(([productListName, response]) => [
        ProductListActions.getMyProductLists(),
        ProductListActions.shareProductListWithUserSuccess({
          productListName: productListName,
          principalList: response
        })
      ]),
      catchError((error) => {
        console.log('Acelasi handler de kkt');
        return EMPTY;
      }))})
    )
  );

the module file:

@NgModule({
  declarations: [],
  imports: [
    CommonModule,
    StoreModule.forFeature("productListState", productListReducer),
    EffectsModule.forFeature([ProductListEffects])
  ],
  providers: [ProductListOccService],
  entryComponents: []
})
export class PrtListStoreModule {}

I debugged this, but I couldn't understand why the effect is called only once.


Solution

  • The problem is in catchError, you need to add repeat after it to enable the effect again.

    
          catchError((error) => { // <- closes the stream
            console.log('Acelasi handler de kkt');
            return EMPTY;
          }))}),
          repeat(), // <- resubscribes
    

    Ideally would be right to put catchError in the .pipe of the .shareProductListWithUser, then you could avoid repeat, but because you have dependencies on the response you can keep the code as it as and to achieve the desired behavior with repeat.