// Cache DOM elements const inputElements = document.querySelectorAll('[data-model]'); const boundElements = document.querySelectorAll('[data-bind]'); const loopElements = document.querySelectorAll('[data-loop]'); /* --- Bind element --- */ function binder(data) { let scope = {} // Add data if (data) { for (const propName of Object.getOwnPropertyNames(data)) { scope[propName] = data[propName]; setBindValue(propName, data[propName]); } } // Loop through input elements for (let el of inputElements) { if (el.type === 'text' || el.type === 'hidden') { // Get property name from each input with an attribute of 'mm-model' let propName = el.getAttribute('data-model'); // Set property update logic setPropUpdateLogic(scope, propName); // Update bound scope property on input change scope[propName] = el.value; el.addEventListener('keyup', e => { scope[propName] = el.value; }); } } return scope; }; function setPropUpdateLogic(scope, prop) { if (!scope.hasOwnProperty(prop)) { let value; Object.defineProperty(scope, prop, { // Automatically update bound dom elements when a scope property is set to a new value set: (newValue) => { value = newValue; // Set input elements to new value for (let el of inputElements) { if (el.getAttribute('data-model') === prop) { if (el.type) { el.value = newValue; } } } // Set all other bound dom elements to new value setBindValue(prop, newValue); }, get: () => { return value; }, enumerable: true }) } } function setBindValue(prop, newValue) { for (let el of boundElements) { if (el.getAttribute('data-bind') === prop) { if (!el.type) { el.innerHTML = newValue; } } } } /* --- For each --- */ function looper(scope) { for (let el of loopElements) { let propName = el.getAttribute('data-loop'); let data = scope[propName]; let html = []; // If data is an array (if not do nothing) if (data && Array.isArray(data)) { // If data is already computed back to the initial value const defaultValue = el.querySelector('[data-looped]') if (defaultValue) { el.innerHTML = defaultValue.innerHTML; } // Add the not computed value html.push(`
${el.innerHTML}
`); // Add info to replace value for (let i = 0; i < data.length; i++) { html.push(el.innerHTML.replace(/data-val="/g, 'data-index="' + i + '" data-val="')); } el.innerHTML = html.join("\n"); // Replace value for the current loop const currentLoopElements = document.querySelectorAll('[data-loop=' + propName + ']'); for (const currentElement of currentLoopElements) { valElements = currentElement.querySelectorAll('[data-val][data-index]'); for (const valElement of valElements) { const val = scope[propName][valElement.getAttribute('data-index')][valElement.getAttribute('data-val')]; if (val) { valElement.innerHTML = val; } } } } } }