JSFiddle - React, Tailwind, and code Playground
HTML
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<meta http-equiv="X-UA-Compatible" content="ie=edge">
<title>Document</title>
</head>
<body>
<div>
<span data-bind="counter"></span>
<button onclick="increment()">Increment</button>
<hr/>
<input data-model="name" />
<input data-model="lastname" />
<button onclick="add()">Add</button><br/>
You are about to add: <span data-bind="name"></span> <span data-bind="lastname"></span>
<table>
<thead>
<tr>
<th>Name</th>
<th>Lastname</th>
</tr>
</thead>
<tbody>
<template data-for="list">
<tr>
<td data-each-bind="$.name"></td>
<td data-each-bind="$.lastname"></td>
</tr>
</template>
</tbody>
</table>
</div>
<script>
/**
* Define the initial state:
* Add `data-bind="counter"` to an html element, it will reload every time the counter is updated
* Add `data-model="name"` to an html input, the state will update every time the input changes
* Add `data-for="list"` to an html template, a list will be created cloning the html first child
**/
let state = new Bynd({
counter: 0,
name: '',
lastname: '',
list: [
{ name: 'ciao', lastname: 'ciaone' },
{ name: 'prova', lastname: 'provetta' },
{ name: '2', lastname: '4' },
]
})
function increment() {
// Update the variable to reload the html elements linked to this variable
state.counter++
}
function add() {
// Push a new element to...
JavaScript
function setNested(obj, path, value) {
var schema = obj;
var pList = path.split('.');
var len = pList.length;
for (var i = 0; i < len - 1; i++) {
var elem = pList[i];
if (!schema[elem]) schema[elem] = {}
schema = schema[elem];
}
schema[pList[len - 1]] = value;
}
function eventifyPush(arr, callback) {
arr.push = function (e) {
Array.prototype.push.call(arr, e);
callback(arr);
};
};
class Bynd {
constructor(variables) {
this.$variables = {}
this.defineProperties(variables)
this.bindModels()
}
defineProperties(variables) {
// Dynamically create getters/setters starting for each variable passed in the costructor
for (let variable in variables) {
let init = variables[variable]
Object.defineProperty(this, variable, {
get: () => this.$variables[variable],
set: v => {
this.$variables[variable] = v;
// Every time the setter is called, reload the html elements that are binded to the variable
this.bind(variable)
this.bindFor(variable)
},
})
this[variable] = init
if (init instanceof Array) {
// Every time the push method (for arrays) is called, reload the html elements that are binded to the variable
eventifyPush(this[variable], (e) => {
this.bind(variable)
this.bindFor(variable)
})
}
}
}
bindModels() {
[...document.querySelectorAll("[data-model]")].forEach(d => {
const queryVariable = d.getAttribute('data-model')
d.oninput = () => {
setNested(this, queryVariable, d.value)
}
})
}
bind(variable) {
/**
* [data-bind^= it means starting with. This is used to search...