angularobservablesubject

Update display for items in shopping cart with Subject/Observable


I'm creating an app where the user adds an item to their cart, and then it keeps track of these items in local storage. When the user clicks on the add button in one component, I need the navbar to update with the number of items in real time but I cannot use an Event Emitter with how my app is set up.

The functionality I'm looking for is simple, when I add an item and it goes into local storage, the number in my navbar next to the shopping cart logo should increase by 1. I know this can be handled using Observables and Subjects, I'm just having a difficult time understanding it. I've moved the code from the component to the service to begin because I figure that will allow both components to communicate with it. I can add the items to local storage properly using the service, but I'm stuck after that where I need to keep track of the number of items added with the service.

Here's the service:

@Injectable({
  providedIn: 'root'
})
export class MenuService {
  public apiRoot: string = `http://localhost:3000`;
  orders;

  constructor(private http: HttpClient) { }

  order(id, name, options, price) {
    //confirm the order is correct
    const orderConfirmed = confirm("Add this item to your cart?");

    if (orderConfirmed) {
    let order = new Order(id, name, options, price)   

    //get and set any existing orders from local storage or set to a blank array if there are none
    this.orders = localStorage.getItem('order') ? JSON.parse(localStorage.getItem('order')) : [];

    //push to our orders array
    this.orders.push(order)

    //store in localStorage
    localStorage.setItem('order', JSON.stringify(this.orders)) 
    }
  }

Then here is my navbar.ts:

export class NavbarComponent implements OnInit {
  itemsInCart;
  constructor() { }

  getItemsInCart() {
    this.itemsInCart = JSON.parse(localStorage.getItem('order'))
  }

  ngOnInit() {
    this.getItemsInCart();
  }

}

Right now I'm just pulling the items directly from local storage and displaying them, but obviously this won't work in real time if I were to add other items, basically I want to make my navbar component which is above the router-outlet to be able to subscribe to the this.orders property in the MenuService so that I can keep track of the length of this.orders in real time as the user adds items to the cart. Sorry if this seems obvious, still learning!


Solution

  • Add a Subject to your service, call it in your order method and subscribe to it in yur component

    storage.service.ts

    orders
    ordersChanged = new Subject<any>()
    
    order(){
       //your code
       this.ordersChanged.next(this.orders)
        }
    

    component.ts

    itemsInCart
    
    constructor(private storageService: StorageService){}
    
    ngOnInit(){
       this.storageService.ordersChanged.subscribe(items => itemsInCart = items)
    }