Skip to content

robots4life/vanilla-counter-observer

Folders and files

NameName
Last commit message
Last commit date

Latest commit

 

History

4 Commits
 
 
 
 
 
 
 
 

Repository files navigation

Vanilla JavaScript Counter - Observer Pattern

The subscription, notification and un-subscription can happen inside the scope of the click handler or in the global scope, depending on other events, however take care of un-subscription on unmount / destroy, or i.e. when navigating to another component / page.

<!DOCTYPE html>
<html lang="en">
  <head>
    <meta charset="UTF-8" />
    <meta name="viewport" content="width=device-width, initial-scale=1.0" />
    <title>Vanilla JavaScript Counter - Observer Pattern</title>
    <style>
      html {
        background-color: #002244;
        color: blanchedalmond;
        font-family: system-ui, -apple-system, BlinkMacSystemFont, "Segoe UI", Roboto,
          Oxygen, Ubuntu, Cantarell, "Open Sans", "Helvetica Neue", sans-serif;
      }
      body {
        padding: 2rem;
        font-size: 1.4rem;
      }
      form,
      input,
      button,
      a {
        font-size: 1.6rem;
      }
      a {
        color: whitesmoke;
      }
      a:hover {
        color: green;
      }
      .prose {
        display: flex;
        flex-direction: column;
        gap: 1.4rem;
      }
      .text {
        font-size: 1.8rem;
        font-weight: bold;
        color: #002244;
        height: 8rem;
        display: flex;
        justify-content: center;
        align-items: center;
        background-color: orange;
        border-radius: 12px;
      }
      button {
        border-radius: 12px;
        padding: 1rem;
      }
    </style>
  </head>
  <body>
    <div class="prose">
      <h1>Vanilla JavaScript Counter - Observer Pattern</h1>
      <p>
        The subscription, notification and un-subscription can happen inside the
        scope of the click handler or in the global scope, depending on other
        events, however take care of un-subscription on unmount / destroy, or
        i.e. when navigating to another component / page.
      </p>
      <p class="text" id="count"></p>
      <p><button id="increment">Increment Count</button></p>
      <p>
        <a target="_blank" href="https://jsfiddle.net/anrc9w3u/"
          >https://jsfiddle.net/anrc9w3u/</a
        >
      </p>
    </div>
  </body>
  <script src="index.js"></script>
</html>
function createCounter(initialCount) {
  let observers = [];
  let count = initialCount;

  function subscribe(func) {
    observers.push(func);
    return unsubscribe;
  }

  function get() {
    observers.forEach((observer) => observer(count));
    return count;
  }

  function set(newCount) {
    count = newCount;
    observers.forEach((observer) => observer(count));
    return count;
  }

  function unsubscribe(func) {
    observers = observers.filter((observer) => observer !== func);
  }

  return {
    subscribe,
    get,
    set,
    unsubscribe,
  };
}

let count = 0;
const counter = createCounter(count);

// The subscription, notification and un-subscription can happen inside the
// scope of the click handler or in the global scope, depending on other
// events, however take care of un-subscription on unmount / destroy, or
// i.e. when navigating to another component / page.

function logger(data) {
  console.log("current count : ", data);
}
counter.subscribe(logger);
// this logs the value a first time
counter.set(123456789);

// this logs the value a second time
counter.get();

const countElement = document.getElementById("count");
// this will update the DOM
// this logs the value a third time
countElement.innerHTML = counter.get();

// const increment = document.getElementById("increment");
increment.addEventListener("click", function (event) {
  // get current count - optional here since count is set external
  // the click event also logs the current value, the fourth time in sequence
  count = counter.get();

  // increment count
  count = count + 1;

  // set new count
  // this logs the new value
  countElement.innerHTML = counter.set(count);

  // as an alternative the subscription, notification and un-subscription
  // can happen inside the scope of the click handler
  /*
  counter.subscribe(logger);
  count = counter.get();
  count = count + 1;
  countElement.innerHTML = counter.set(count);
  counter.unsubscribe(logger);
  */
});