One-directional data binding without frameworks

One-directional data binding without frameworks

by   Jack Tarantino  |  March 2, 2018  |  4

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.

The following article is one in a series about writing client-focused JavaScript without the help of libraries and frameworks. It’s meant to remind developers that they can write good code on their own using nothing but native APIs and methods. For more, check out the original article on writing small JavaScript components without frameworks and the previous article on templates and rendering.
This article is intended to be a deep-dive into data-binding, how it works, and how you can do it without frameworks like Angular, React, or Ember. It is strongly recommended that you read the previous article before this one.

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…

Sign up for InRhythm updates: IR events, tech news, and more!

4 Comments

    • 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.

    • 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!

Leave a Reply




check out our new interactive scrum framework