Search code examples
javascriptangulartypescriptionic-frameworkbehaviorsubject

Angular BehaviorSubject pass value to a component


I am in need of some help and assistance with BehaviorSubject in Angular. I have an app that has a footer component in which I would like to display the number of products in cart.

I get the amount of products in cart and other cart data over API. Here is how the cart data from API looks like:

shopping-cart.ts

export interface ShoppingCart {
  total_products: number;
  totals: number;
  notes: string;
  shipping_method: string;
}

Here is the API call to get all the cart data: cart.service.ts

  getCart() {
    return from(Preferences.get({key: 'TOKEN_KEY'})).pipe(
      switchMap(token => {
        const headers = new HttpHeaders().set('Authorization', `Bearer ${token.value}`);
        return this.httpClient.get<ShoppingCart>(`${environment.apiUrl}cart`, {headers, observe: 'response'});
      }),
      catchError(err => {
        console.log(err.status);
        if (err.status === 400) {
          console.log(err.error.message);
        }
        if (err.status === 401) {
          this.authService.logout();
          this.router.navigateByUrl('/login', {replaceUrl: true});
        }
        return EMPTY;
      }),
    );
  }

Here is the code in cart.page.ts where I am getting the cart data:

  getCart() {
    this.getCartSubscription = this.cartService.getCart().subscribe(
      (data: any) => {
        const productsData = data.body.products;
        const totalProducts = data.body.total_products;
        const totalCartPrice = data.body.totals;
        this.products = productsData.map(products => products);
        this.totalProducts = totalProducts;
        this.totalCartPrice = totalCartPrice;
        console.log('Products in cart:', data.body);
      },
      error => {
        console.log('Error', error);
      });
  }

Here is how I was attempting to send data to my footer component: in the cart.service.ts file I have added this code:

  shopingCartData: ShoppingCart;

  private cartQtySource = new BehaviorSubject(this.shopingCartData);
  currentValue = this.shopingCartData.total_products;

  constructor(
    ...some other code...
  ) { }

  getCartQty(qty: number) {
    this.cartQtySource.next(qty);
  }

How do I send the data of number of products in the cart from cart page to the footer component so I always get the current ammount?


Solution

  • In cart.service.ts

    you cannot do

      private cartQtySource = new BehaviorSubject(this.shopingCartData);
      currentValue = this.shopingCartData.total_products;
    

    because shopingCartData has only been declared and has no data, and it will throw an error.

    instead you can do:

    private cartQtySource = new BehaviorSubject(0);
    cartQtySource$ = this.cartQtySource.asObservable();
    

    You already have getCartQty() in place, so you can use it directly in cart.page.ts like below:

    getCart() {
        this.getCartSubscription = this.cartService.getCart().subscribe(
          (data: any) => {
            const productsData = data.body.products;
            const totalProducts = data.body.total_products;
            const totalCartPrice = data.body.totals;
            this.products = productsData.map(products => products);
            this.totalProducts = totalProducts;
            this.totalCartPrice = totalCartPrice;
            this.cartService.getCartQty(totalProducts);
            console.log('Products in cart:', data.body);
          },
          error => {
            console.log('Error', error);
          });
      }
    

    Also, getCartSubscription has been made on httpClient observable, so you don't have to unsubscribe to it manually, angular will handle it.

    Lastly, you just need to get these values in your footer.component.ts, which you can do like this:

    export class FooterComponent implements OnInit {
      private getCartSubscription: Subscription;
      constructor(private cartService: CartService) {}
      totalProducts = 0;
    
      ngOnInit() {
        this.cartService.cartQtySource$.subscribe((tp: number) => {
          this.totalProducts = tp
          console.log('Numbner of products: ', this.totalProducts);
        });
      }
    }