// Cache DOM elements const inputElements = document.querySelectorAll('[mm-model]'); const boundElements = document.querySelectorAll('[mm-bind]'); // Initialize scope variable to hold the state of the model. let scope = {}; function init() { // Loop through input elements for (let el of inputElements) { if (el.type === 'text') { // Get property name from each input with an attribute of 'mm-model' let propName = el.getAttribute('mm-model'); // Update bound scope property on input change el.addEventListener('keyup', e => { scope[propName] = el.value; }); // Set property update logic setPropUpdateLogic(propName); } } }; function setPropUpdateLogic(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('mm-model') === prop) { if (el.type) { el.value = newValue; } } } // Set all other bound dom elements to new value for (let el of boundElements) { if (el.getAttribute('mm-bind') === prop) { if (!el.type) { el.innerHTML = newValue; } } } }, get: () => { return value; }, enumerable: true }) } } init(); // Set initial scope values scope.firstname = 'John'; scope.lastname = 'Doe';
<form> <label for="name">First Name:</label> <input type="text" id="name" placeholder="Start typing..." mm-model="firstname"> <h1 mm-bind="firstname"></h1> <label for="name">Last Name:</label> <input type="text" id="name" placeholder="Start typing..." mm-model="lastname"> <h1 mm-bind="lastname"></h1> </form>