1

New to Angular. Wanted to learn how to manage state centrally so used ngRx. Also, have not used an Observable before so I am really stuck. Below is my code where the cart holds and array of objects. I just need to iterate over the cart which is array of objects with reduce() to get a total of the price. No matter what I try it does not work. Just to add, up till this point my code is working fine and I am able to get cart data from the store. Appreciate if someone can guide me in the right direction.

Thank you!

import { Component } from '@angular/core';
import { Store, select } from '@ngrx/store';
import { Observable } from 'rxjs';

@Component({
  selector: 'app-cart-icon',
  templateUrl: './cart-icon.component.html',
  styleUrls: ['./cart-icon.component.scss']
})
export class CartIconComponent {

  constructor(private store: Store<any>) {}

  cart: Observable<Array<any>>

  ngOnInit() {
    this.cart = this.store.select('cart')
  }
}
sayayin
  • 971
  • 5
  • 23
  • 36

1 Answers1

0

If the cart is an array of objects with form {price: number}, use the pipe reduce method with a subscribe to materialize the value in concrete form.

totalPrice: number;

ngOnInit() {
    this.store.select('cart').pipe(reduce((acc, val) => { return { price: acc.price + val.price } } )).subscribe(val=> this.totalPrice = val.price);
}

Alternatively just use the pipe reduce method to keep the value as an observable for rendering directly in the HTML file using async pipes (more efficient if thats what you would like to achieve)

total = Observable<any>;

ngOnInit() {
    this.totalPrice = this.store.select('cart').pipe(reduce((acc, val) => { return { price: acc.price + val.price } } ));
}

The async pipe in the last case would take form <span>{{(total | async)?.price}}</span>

jamesioppolo
  • 457
  • 1
  • 7
  • 15
  • Thanks for your reply. I was getting undefined for the val so I started to troubleshoot like this: this.store.select('cart').pipe(reduce((accumalatedTotal, cartItem) => accumalatedTotal + (cartItem.price), 0)) //this.store.select('cart').pipe(map((cartItem) => cartItem)) .subscribe((val:number) => console.log("===>>>", val)); With that commented out map I can print the item but I cannot see anything with reduce. Can u see what could be wrong here?.Also, can you please update your code in subscribe to be val:number as ts was giving me an error. – sayayin Sep 02 '20 at 16:15
  • To make the reduce simpler even this does not return anything whereas if I replace with map, it returns back the cartItem. this.store.select('cart').pipe(reduce((accumalatedTotal, cartItem) => cartItem)) – sayayin Sep 02 '20 at 16:45
  • Also tried the second option and I have the following in component html but it prints as an object.
    Total: {{ totalPrice | async }}
    – sayayin Sep 02 '20 at 17:40
  • I'm thinking may be it has something to do with the reduce() behavior like specified in the comments for this post: https://stackoverflow.com/questions/56021653/angular-rxjs-reduce-never-completes Trying out things but still not sure how to fix – sayayin Sep 02 '20 at 17:51
  • I have updated the answer in the case where the cart is an array of objects { price: number } – jamesioppolo Sep 03 '20 at 05:49
  • any suggestions for my comments above? I have no been able to resolve the issue – sayayin Sep 03 '20 at 13:19
  • yes, in order to resolve this question, can you please confirm the type of object in the cart. I need the name and type, ie { price: number } – jamesioppolo Sep 03 '20 at 20:50
  • I have not used any types for this mock data that im using. Each item in array looks like: { id: 1, name: 'Burgundy T-shirt', imageUrl: './assets/img/polka-dot-shirt.png', price: 25 } – sayayin Sep 04 '20 at 00:08