DEV Community

Cover image for One-way data binding in vanilla JS (POC)
Francesco Esposito
Francesco Esposito

Posted on • Updated on <time datetime="2019-02-02T22:26:43Z" class="date">Feb 2, 2019</time>

One-way data binding in vanilla JS (POC)

Code and Demo

Let's break it down in small pieces

I assume you are already familiar with data-binding.

Most of the modern front-end frameworks offer data-binding out of the box, just ready to use, but what there is under the hood?

I tried to implement a basic version of one-way data binding and it was really fun :)

So, what do we need to have one-way data binding?

  • A view, in our example HTML.
  • A state, kept in memory with JavaScript.

The Key feature is:

Everytime the state changes, the view need to be updated

So let's assume we have an HTML view:

    <div data-binding="quote"></div>

and a state:

    const state = {
      quote: 'Either you run the day, or the day runs you.'
    };

We can easily set the view the first time:

    document.querySelector('[data-binding="quote"]').innerHTML = state.quote

We want some magic, so that when we update the state:

    state.quote = 'We become what we think about'

the view should magically change. To achieve this, we could modify the default behaviour of the set property for the state object, so that other than update the model, it would also update our view.

One way to do that in JavaScript is using the Proxy Object:

    const createState = (state) => {
      return new Proxy(state, {
        set(target, property, value) {
          target[property] = value; // default set behaviour
          render(); // updates the view everytime the state changes
          return true;
    }
      });
    };

    const state = createState({
      quote: 'Either you run the day, or the day runs you.' // creates initial state
    });

With the power of the Proxy everytime we update our state, the render function will be called.
A possible implementation of render can be:

    const render = () => {
     document.querySelector('[data-binding="quote"]').innerHTML = state.quote
    };

Now if we modify the state with:

    state.quote = 'We become what we think about.'

The render function will be called and the view will update! MAGIC! 👨‍💻

Discussion (14)

Collapse
berslucas profile image
Lucas Bersier • Edited on

I like this, I didn't do anything with Proxies before.

One thing with this demo is that it will only update state.quote, with a few changes it can be generic and you can update multiple elements.

const createState = state => {
  return new Proxy(state, {
    set(target, property, value) {
      target[property] = value; 
      render(property);
    }
  });
};

const render = property => {
  document.querySelector(`[data-binding="${property}"]`).innerHTML = state[property];
};
    <div data-binding="quote1"></div>
    <div data-binding="quote2"></div>
state.quote1 = 'hello';
state.quote2 = 'world';

Also, I don't see any documentation for returning in the Proxy function. Is this just a code style thing or is return true useful for something in this case?

Collapse
phoinixi profile image
Francesco Esposito Author • Edited on

Thanks Lucas for your comment, if you check out the code and demo (I should maybe include that in the post) you will see that it's more generic :)
return true is necessary, otherwise, you will get an error:

developer.mozilla.org/en-US/docs/W...

Collapse
berslucas profile image
Lucas Bersier

Gotcha. Thanks

Collapse
link2twenty profile image
Andrew Bone

Just so you know you can embed stackblitz project right into your post with the following syntax 🙂

{% stackblitz one-way-data-binding %}

Collapse
phoinixi profile image
Francesco Esposito Author

Hi Andrew, thanks! I did that initially but then I preferred the external link and to break down the concepts later in the article

Collapse
link2twenty profile image
Andrew Bone

Ah, ok 🙂

Thread Thread
phoinixi profile image
Francesco Esposito Author

eventually, I followed your advice 😉

Thread Thread
briancodes profile image
Brian • Edited on

The Stackblitz preview doesn't seem to run on mobile (Android Chrome)

I use StackBlitz on my own site, it's great on desktop, but causes some mobile browsers to crash. CodeSandbox has a light embed option which looks promising

Collapse
megazear7 profile image
megazear7

I love the simplicity of this. I would never have guessed that it would be so simple!

Very informative, thank you!

Collapse
shivanisdev profile image
Shivani Sehdev

I could not find anywhere how this set(argument1, argument2, argument3) works.
When I search for set function in javascript it takes me SETS.
I want to know, how every object has that set() method associated with it.

Collapse
shivanisdev profile image
Shivani Sehdev

I found it actually
developer.mozilla.org/en-US/docs/W...
It is the Proxy Handler

Collapse
chenge profile image
chenge

Good, what is POC?

Collapse
phoinixi profile image
Francesco Esposito Author

Proof Of Concept :)

Collapse
frgarciames profile image
frgarciames

Proof of Concept 🙂