<div id="root">
<h1>Vanilla JS - Two way binding using Proxy</h1>
<div class="form-group">
<div class="form-elements">
Name: <input data-bind="username" type="text" />
<br/>
<span data-bind="username"></span>
<br/><br/>
Email: <input data-bind="email" type="text"/>
<br/>
<span data-bind="email"></span>
</div>
<div class="button-group">
<button onclick="log()">Inspect Scope</button>
<button onclick="changeUsernameByCode()">Change Username Scope</button>
<button onclick="changeEmailByCode()">Change Email Scope</button>
</div>
</div>
<div id="debug-container">
<button id="btnClearLog" title="Clear logs" onclick="clear_logs()">x</button>
<pre id="debug">
</pre>
</div>
</div>
@import url(https://fonts.googleapis.com/css?family=Roboto:400,100,500,300italic,500italic,700italic,900,300);
html{
color: rgba(33, 33, 33, 0.87);
}
body{
font-family: "Roboto", 'Helvetica Neue, Helvetica, Arial';
margin:0;
padding:0;
background: black;
color: white;
font-size: 1.3em;
}
#root {
width: 100%;
}
h1 {
}
.form-group{
display: flex;
flex-direction: row;
flex: 3;
}
.form-elements {
padding: 10px;
}
.form-elements span {
color: #ff4500;
}
.button-group {
margin: 0;
order: -1;
display: flex;
flex-direction: column;
font-size: 1rem;
height: 100vh;
background: #2b0c46;
/* flex-wrap: wrap; */
}
.button-group button {
margin: 5px;
}
#debug-container {
position: fixed;
left: 0;
min-height: 40px;
max-height: 20vh;
bottom: 0;
width: 100%;
background: #0e6b0e;
margin: 0;
padding: 10px;
border:0;
overflow-y: auto;
}
#debug {
position: relative;
overflow-wrap: break-word;
overflow-y: auto;
overflow-x: hidden;
min-height: 20vh;
max-height: 20vh;
}
#btnClearLog {
position:fixed;
right: 10px;
bottom:135px;
width:25px;
height:25px;
}
console.clear();
/* proxy code */
const handler = {
get: function(obj, prop) {
return obj[prop] ;
},
set: function(obj, prop, value) {
obj[prop] = value;
elms.forEach((elm) => {
if (elm.getAttribute("data-bind") == prop) {
// Only supporting text and textarea
// => Feel free to add support for more
if (elm.type && (elm.type === "text" || elm.type === "textarea")) {
elm.value = value;
} else if (!elm.type) {
elm.innerHTML = value;
}
}
})
return true;
}
};
let elms = document.querySelectorAll("[data-bind]");
let debug = document.querySelector("#debug");
debug.innerHTML = "";
let scope = {}; // stores data
scope = new Proxy(scope, handler);
elms.forEach((elm) => {
if (elm.type === "text" || elm.type === "textarea") {
let propToBind = elm.getAttribute("data-bind");
elm.addEventListener("keyup", (e) => {
scope[propToBind] = elm.value; // proxy set method fires
});
}
});
var clear_logs = function () {
debug.innerHTML = "";
}
const log = function () {
Object.keys(scope).forEach((k) => {
debug.innerHTML += JSON.stringify(scope) + "<br/>";
});
debug.scrollTop = debug.scrollHeight;
}
const changeUsernameByCode = function () {
scope.username = "username Changed by Code";
}
const changeEmailByCode = function () {
scope.email = "email changed by Code";
}
This Pen doesn't use any external CSS resources.
This Pen doesn't use any external JavaScript resources.