Angular getting cartSize with async pipe not working

Mathew

I'm trying to get the size of my cart using the async pipe:

<h1>
  {{cartSize$ | async}}
</h1>

The component where the observable is defined is:

export class ProductsComponent {
  cart$: Observable<Product[]>;
  cartSize$: Observable<number>;
  products: Product[] = [];
  constructor(
    private walmartService: WalmartService,
    private store: Store<AppState>
  ) {
    this.cart$ = this.store.pipe(select(selectCart));
    this.cartSize$ = this.store.pipe(select(selectCartSize));
  }

  ngOnInit(): void {
    this.walmartService
      .getProducts()
      .subscribe((products) => (this.products = products));
  }
  addOne(product: Product): void {
    this.store.dispatch(addOneItem({ payload: product }));
  }

  removeOne(product: Product): void {
    this.store.dispatch(removeOneItem({ payload: product }));
  }

  removeAll(): void {
    this.store.dispatch(removeAll());
  }

  removeItem(product: Product): void {
    this.store.dispatch(removeItem({ payload: product }));
  }
}

and the relevant reducer info like so:

export interface AppState {
  cart: CartState;
}

export interface CartState {
  cart: Product[];
  cartSize: number;
}

export const initialState: AppState = {
  cart: {
    cart: [],
    cartSize: 10,
  },
};

export const selectCartState = (state: AppState) => state.cart;
export const selectCartSize = createSelector(
  selectCartState,
  (state: CartState) => state.cartSize
);
export const selectCart = createSelector(
  selectCartState,
  (state: CartState) => state.cart
);

However, nothing is showing on the page and I'm not sure why. Any idea why?

Initially, I didn't even want to make the cartSize prop in the store because each Product has a count and I could simply reduce it from the total cart of products. But then I ran into some issues with piping and reducing the cart observable and decided to go this route. If there's a better way to get the cart size especially since each product has a count prop, please let me know!

marcel

Use this.store.select not .pipe.

And here is how you can get rid of the separate count varialble:

readonly cartSize$ = this.store.select(selectCart()).pipe(
  map((products: Product[]) => {
    return products.reduce((total: number, { quantity }: Product) => total + quantity, 0);
  }),
  shareReplay(1)
);

I assume the "count"-variable of Product is called quantity, but you can change it if needed.

I use shareReplay(1) to make it a hot observable, so when you subscribe to it multiple times, it won't run each time. In this case it is not necessary, since you only subscribe to it once (using async pipe), but I think it is always a good idea to use hot observables when writing declarative.

Collected from the Internet

Please contact [email protected] to delete if infringement.

edited at
0

Comments

0 comments
Login to comment

Related