Angular Signal-Based Shopping Cart Store

Angular Signal-Based Shopping Cart Store

Angular Signal-Based Shopping Cart Store

A standalone cart service that any component can inject — no NgRx needed for this scale.

// stores/cart.store.ts
import { Injectable, signal, computed } from '@angular/core';

export interface CartItem {
  id:       number;
  name:     string;
  price:    number;
  quantity: number;
}

@Injectable({ providedIn: 'root' })
export class CartStore {
  private _items = signal<CartItem[]>([]);

  readonly items     = this._items.asReadonly();
  readonly itemCount = computed(() => this._items().reduce((s, i) => s + i.quantity, 0));
  readonly total     = computed(() => this._items().reduce((s, i) => s + i.price * i.quantity, 0));

  add(product: { id: number; name: string; price: number }): void {
    this._items.update(items => {
      const existing = items.find(i => i.id === product.id);
      if (existing) {
        return items.map(i => i.id === product.id ? { ...i, quantity: i.quantity + 1 } : i);
      }
      return [...items, { ...product, quantity: 1 }];
    });
  }

  remove(id: number): void {
    this._items.update(items => items.filter(i => i.id !== id));
  }

  updateQuantity(id: number, quantity: number): void {
    if (quantity <= 0) { this.remove(id); return; }
    this._items.update(items =>
      items.map(i => i.id === id ? { ...i, quantity } : i)
    );
  }

  clear(): void { this._items.set([]); }
}
// Usage in any component
readonly cart = inject(CartStore);

// Template
// Total: {{ cart.total() | currency }}
// Items: {{ cart.itemCount() }}
All Comments