<input type="text" id="newItem">
<button id="addItem">Add Item</button>
<div>Total items: <span id="itemCountEl">0</span></div>
<ul id="itemListEl"></ul>
// Classess
class Observable {
  #value;
  #subscribers = [];

  constructor(value) {
    this.#value = value;
  }

  get value() {
    return this.#value;
  }

  set value(newValue) {
    this.#value = newValue;
    this.notify();
  }

  subscribe(observer) {
    this.#subscribers.push(observer);
  }

  unsubscribe(observer) {
    this.#subscribers = this.#subscribers.filter(sub => sub !== observer);
  }

  notify() {
    this.#subscribers.forEach(subscriber => subscriber(this.#value));
  }
}
class Computed extends Observable {
  #dependencies;
  
  constructor(computeFunc, dependencies) {
    // Call the Observable constructor with the initial computed value
    super(computeFunc());
    this.#dependencies = dependencies;
    
    // Define listner to run on dependencies change
    const listner = () => {
      this.value = computeFunc(); // Compute again
    };
    
    // Subscribe to each dependency and run the listner
    this.#dependencies.forEach(dep => dep.subscribe(listner));
  }
}

// Cart Logic
const itemList = new Observable([]);
const itemCount = new Computed(() => itemList.value.length, [itemList]);

addItem.addEventListener('click', () => {
  if (newItem) {
    itemList.value = [...itemList.value, newItem.value]; // Add the new item
    newItem.value = ''; // Reset input field
  }
});

// Subscribe to update the UI whenever itemCount changes
itemCount.subscribe(count => {
  itemCountEl.textContent = count;
  itemListEl.innerHTML = itemList.value.map(item => `<li>${item}</li>`).join('');
});

External CSS

This Pen doesn't use any external CSS resources.

External JavaScript

This Pen doesn't use any external JavaScript resources.