Search code examples
angularngrxngrx-storengrx-effects

NgRx - Get error validation from backend and pass to component


Im trying to grab the errors messages from api and show inside my form inputs so the user can see whats is wrong with the data that is being submitted.

Response From API:

{
  "message": "The given data was invalid.",
  "errors": {
    "name": [
      "This name is already in use."
    ]
  }
}

user-form.component.ts

this.store.dispatch(new actions.CreateUser(user));

user.effect.ts

@Effect()
  CreateUser$: Observable<Action> = this.actions$.pipe(
    ofType(UserActions.CREATE_USER),
    map((action: UserActions.CreateUser) => action.payload),
    switchMap(payload => {
      return this.userService.save(payload).pipe(
        map((user: User) => {
          return new UserActions.CreateUserSuccess(user);
        }),
        catchError(err => {
          return of(new UserActions.CreateUserFail());
        })
      );
    })
  );

How can I grab that error and pass it back to my component?

Should I do like inside the effects and subscribe it to the Actions waiting for an CreateUserFail error? Im not sure if its a good practice since it will listen to all kind of Actions.


Solution

  • We built a selector and subscribed to that selector.

    Effect

      @Effect()
      createProduct$: Observable<Action> = this.actions$.pipe(
        ofType(productActions.ProductActionTypes.CreateProduct),
        map((action: productActions.CreateProduct) => action.payload),
        mergeMap((product: Product) =>
          this.productService.createProduct(product).pipe(
            map(newProduct => (new productActions.CreateProductSuccess(newProduct))),
            catchError(err => of(new productActions.CreateProductFail(err)))
          )
        )
      );
    

    Reducer

    case ProductActionTypes.CreateProductFail:
      return {
        ...state,
        error: action.payload
      };
    

    Selector

    export const getError = createSelector(
      getProductFeatureState,
      state => state.error
    );
    

    Component

    // Watch for changes to the error message
    this.errorMessage$ = this.store.pipe(select(fromProduct.getError));
    

    Template

    <div *ngIf="errorMessage$ | async as errorMessage" class="alert alert-danger">
      Error: {{ errorMessage }}
    </div>
    

    You can find the complete example here: https://github.com/DeborahK/Angular-NgRx-GettingStarted/tree/master/APM-Demo4