This post is another by InRhythm’s own Jack Tarantino. For the full post and additional links, check out the original “Frameworkless JavaScript Part 3: One-Way Data Binding” on his website.
1-way data-binding
1-way data-binding is “a method of putting data into the DOM which updates whenever that data changes”. This is the major selling point of the React framework and with a little effort you can set up your own data binding with much less code. This is particularly useful when you have an application that sees routine changes to data like a simple game, a stock ticker, or a twitter feed; objects needs to have data pushed to the user but no user feedback is required. In this case, we need an object with some data in it:
let data_blob = {
movie: 'Iron Man',
quote: 'They say that the best weapon is the one you never have to fire.'
}
A Proxy:
const quote_data = new Proxy(data_blob, {
set: (target, property, value) => {
target[property] = value
console.log('updated!')
}
})
And a poor DOM node to be our guinea pig:
<p class="js-bound-quote">My favorite {{ movie }} quote is "{{ quote }}".</p>
In this case, we need the data_blob
to serve as a storage unit for the proxy. Proxies in ES6 are a convenient way to trigger callbacks when certain actions are taken on an object. Here, we’re using the proxy to trigger a callback every time somebody changes a value in the data blob. We don’t have a way to update the text in the DOM node yet though so let’s set that up:
const quote_node = document.querySelector('.js-bound-quote')
quote_node.template = quote_node.innerHTML
quote_node.render = function render (data) {
this.innerHTML = this.template.replace(/\{\{\s?(\w+)\s?\}\}/g, (match, variable) => {
return data[variable] || ''
})
}
This gives us a quick and dirty way to update the node’s inner HTML with some arbitrary data. The only thing needed to connect our new script with the proxy is to substitute the console.log
call with quote_node.render(data_blob)
:
const quote_data = new Proxy(data_blob, {
set: (target, property, value) => {
target[property] = value
quote_node.render(data_blob)
}
})
With all this setup, we can add a quick script to prove that our DOM node is, in fact, updated every time we change the data blob. The exact same way that we want things to happen with a framework but with no external dependencies and WAY less code.
const quotes = [
"What is the point of owning a race car if you can't drive it?",
"Give me a scotch, I'm starving.",
"I'm a huge fan of the way you lose control and turn into an enormous green rage monster.",
"I already told you, I don't want to join your super secret boy band.",
"You know, it's times like these when I realize what a superhero I am."
]
window.setInterval(() => {
const quote_number = Math.floor(Math.random() * quotes.length)
quote_data.quote = quotes[quote_number]
}, 2000)
This adds a script to change to a random quote every two seconds. Check out the working example below:
This is a little sloppy, as it only works for one node, one time. Let’s clean things up a bit and add constructors for both the nodes and Proxies. Continue reading on jack.ofspades.com…
i like it 🙂 but isn’t the proxy here just a quick way to get a reactive model ? like vue’s computed props for example ?
Yes! Exactly! 😀 . I wanted a callback to be fired whenever I changed a value. The
Proxy
API gives you exactly that. It’s a really powerful API but it’s also a little esoteric I think. I’m under the impression that it’s not very widely used and I think that’s why. The advantage over something like Vue’s computed props is that this API is JavaScript-native and thus eligible for more under-the-hood optimizations than a framework that implements its own version.Nice post, the whole series, I’ve been always advocating for Vanilla JS/CSS/HTML.
Thank you! I feel like I frequently struggle to explain to people that I’m not against frameworks categorically. I just think that people need to take a moment before deciding which architecture to use and that a deeper knowledge of JS and especially newer features make a lot of framework aspects obsolete. Templating is a big one for me. You can write a simple function to do templating that has a simple API and just run with it. Of course now JS has that build in too so you can just use template string literals. Don’t even need to write your own parser!