Very Basic JavaScript Framework


Introduction

I was creating a simple calculator for stock options and wanted a very basic way of binding values and events. The design and formulas kept changing as I was learning stuff and it became difficult to keep track of everything with just basic vanilla JS. So, I needed a framework to tie everything up. Instead of using a framework or library I thought I’ll write a simple version of what I need. Specific enough to solve my problem and generic enough to reuse.

My requirements are simple, a way to bind data input elements so when they change they keep the same value. Second requirement was to trigger an evaluation function whenever I change one of the values in the calculator formula.

Getting Values

I needed a simple wrapper to get the string and number given the id of the element.

function getString(id) {
  var elem = document.getElementById(id);
  if (elem === null || elem === undefined) {
    return "";
  }

  return elem.innerHTML.trim().replace(/[,\/#!$%\^&\*;:{}=\-_`~() ]/g, "");
}

function getNumber(id) {
  var n = parseFloat(getString(id));
  if (isNaN(n)) {
    return 1.0;
  }
  return n;
}

getNumber returns 1.0 by default to prevent divide by zero error, which is specific to what I wanted to do.

Updating Values

A routine to update all children elements if the value of parent changes.

function updateValues(parent, children, valtype) {
  var mval = null;
  switch (valtype) {
    case "string":
      mval = getString(parent);
      break;
    case "double":
      mval = getNumber(parent);
      break;
    default:
      mval = getString(parent);
      break;
  }
  for (var i = 0; i < children.length; i++) {
    var elem = document.getElementById(children[i]);
    if (elem === null || elem === undefined) {
      continue;
    }
    elem.innerHTML = mval;
  }
}

Binding Events

I wrote a generic way to bind a set of ids together for a particular event and a datatype. If one of the elements triggers an event all others will get the same value using the function defined above : updateValues.

function addBoundEvents(ids, event, valtype) {
  for (var i = 0; i < ids.length; i++) {
    for (var j = 0; j < ids[i].length; j++) {
      let parent = ids[i][j];
      let children = ids[i].filter(function (item) {
        return item != parent;
      });
      let elem = document.getElementById(parent);
      if (elem === null || elem === undefined) {
        continue;
      }
      elem.addEventListener(event, function () {
        let m = parent;
        let s = children;
        updateValues(m, s, valtype);
      });
    }
  }
}

Reactive Ids

Along with updating values I needed a way to trigger compute methods on values to get some output. For that I defined a data structure to represent these relationships in JSON format and another routine to bind events with the compute method.

var reactiveids = [
  {
    ids: [],
    event: "keyup",
    method: () => {},
  },
];

function bindReactiveIds(reactiveids) {
  for (var i = 0; i < reactiveids.length; i++) {
    for (var j = 0; j < reactiveids[i]["ids"].length; j++) {
      var elem = document.getElementById(reactiveids[i]["ids"][j]);
      if (elem === null || elem === undefined) {
        continue;
      }
      elem.addEventListener(reactiveids[i]["event"], reactiveids[i]["method"]);
    }
  }
}

Using the Framework

With this framework at hand I could easily write my HTML with distinct ids. Later it was just a matter of defining relationships and binding events.

// binding ids to share same values (string or double)
var boundids_string = [["in-title", "out-title"]];
var boundids_double = [
  ["in-val-a", "out-val-a"],
  ["in-val-b", "out-val-b"],
];
addBoundEvents(boundids_string, "keyup", "string");
addBoundEvents(boundids_double, "keyup", "double");

// computed values
var computedVala = () => getNumber("in-val-a");
var computedValb = () => getNumber("in-val-b");

// compute method
function methodValSum() {
  var elem = document.getElementById("out-sum-ab");
  outstr = (computedVala() + computedValb()).toString();
  elem.innerHTML = outstr;
}

// reactive relationship
var reactiveids = [
  {
    ids: ["in-val-a", "in-val-b"],
    event: "keyup",
    method: methodValSum,
  },
];
bindReactiveIds(reactiveids);

Final Result

{{< renderhtml `

See the Pen Bind HTML elements using Vanilla JS by ranuzz (@ranuzz) on CodePen.

`>}}