How to catch an error on a component in Angular using RXJS

68 views Asked by At

I'm trying to refactor a code that triggers an API request, the error is being caught on the service, I want to catch the error on the component.ts file but for some reason when I try to subscribe to it the success block is being triggered even if it errors out.

The flow is, on component.ts file an action is being triggered, then effects handles it next, and then finally the service which calls the API.

Code:

component.ts

 addToCart() {
    combineLatest(
      this.product$,
      this.variantId$,
      this.specTemplateStatusAndValue$.pipe(
        map((statusAndValue) => statusAndValue.value)
      )
    )
      .pipe(
        takeUntil(this.unsubscribe$),
        first(),
        flatMap(([product, variantId, specTemplateValue]) => {
          this.store.dispatch(
            this.checkoutActions.addToCart(
              variantId,
              product.normal_product ? 1 : 1,
              specTemplateValue,
              []
            )
          );
          return of(null);
        })
      )
      .subscribe(
        (res) => {
          console.log('subs', res);
          return this.router.navigate(['/checkout', 'cart']);
        },
        (err) => console.error(':::::ERROR', err)
      );
  }

action.ts

 addToCart(
    variant_id: number,
    quantity: number,
    spec_template_value: any = {},
    addon_value_ids = []
  ): any {
    return {
      type: CheckoutActions.ADD_TO_CART,
      payload: {
        variant_id,
        quantity,
        spec_template_value,
        addon_value_ids: addon_value_ids
      }
    };
  }

effect.ts

  @Effect()
  addToCart$ = this.actions$.pipe(
    ofType(CheckoutActions.ADD_TO_CART),
    flatMap((action: any) => {
      return this.checkoutService.createNewLineItem(action.payload);
    }),
    map((result) => {
      return this.actions.addToCartSuccess();
    })
  );

service.ts

 createNewLineItem(payload) {
    return of(null).pipe(
      tap(() => {
        this.store.dispatch(this.actions.loadingCurrentOrder());
      }),
      flatMap(() => this.fetchCurrentOrder()),
      flatMap((order) => {
        console.log(order, 'ASDASD');
        return this.http.post<Order>(
          `spree/api/v1/orders/${order.number}/line_items?order_token=${order.token}`,
          this.createLineItemPayload({
            variant_id: payload.variant_id,
            quantity: payload.quantity,
            spec_template_value: payload.spec_template_value,
            addon_value_ids: payload.addon_value_ids,
            coupon_claim_id: payload.coupon_claim_id
          })
        );
      }),
      tap((order) => {
        this.store.dispatch(this.actions.fetchCurrentOrderPreProcess(order));
      }),
      finalize(() => {
        this.store.dispatch(this.actions.loadedCurrentOrder());
      })
    );
  }
1

There are 1 answers

1
Matthieu Riegler On

You won't be able to catch directly the error on the component since you dispatching an effect (which is synchronous).

Your alternative is to:

  1. catch the error in the effect
  2. map it to an error action
  3. listen to that error action in the component (by injecting actions$ in the component).