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.
`>}}