Simple two-way data binding between DOM and data. No modern browser necessary, supported everywhere document.querySelector
is (though IE9+ is helpful for using Object.defineProperties
to broadcast changes).
All examples of two-way binding I could find required using Object.observe (which requires a pollyfil), needed a JavaScript function that you pass all your bindings and DOM selectors, only updated the changed binding and didn't check for other bindings that relied on it, or a larger library. I wanted something small, that could work everywhere, propagated changes to all bindings, and allowed the DOM to define the bindings. So I wrote the code that would do it.
The code works by mapping DOM elements to JavaScript objects through the use of the data-bind
attribute. The attribute's value is a path to the object property to bind to. Once a map from DOM element to object is created, all you have to do is call updateBindings
whenever a value changes and the code will dirty check all bound properties for changes and update the DOM accordingly. Inputs will automatically call updateBindings
on change
events.
The only requirement is that all bindings must be attached to a single object, and that object must be passed into the two-way binding function call.
The code will attach 5 functions to your object that can be used in your code to broadcast changes or work with the bindings.
-
getBoundObject(path)
- returns the object of a binding. Pass it thedata-bind
attribute.getBoundObject('person.name'); //=> person
-
getBoundProperty(path)
- returns the property of a binding. Pass it thedata-bind
attribute.getBoundProperty('person.name'); //=> 'name'
-
getBoundValue(path)
- returns the value of a binding. Pass it thedata-bind
attribute.person.name = 'John Doe'; getBoundValue('person.name'); //=> 'John Doe'
-
updateBindings()
- broadcast a binding change and update the DOM if any bindings have changed. -
bindDom(node)
- parse a DOM node fordata-bind
attributes and bind them to their objects. Use to bind any JavaScript created elements after the page has loaded.
<!-- simple html binding -->
<span data-bind="person.name"></span>
<!-- input binding -->
<input type="text" data-bind="person.address"/>
<script>
var person = {
name: 'John Doe',
address: 'unknown location'
};
// two-way bind the person object to the DOM
twoWayBind(person);
</script>
<!-- use Object.defineProperties to broadcast changes in JavaScript to the DOM -->
<input type="text" data-bind="person.age" readonly/>
<script>
person = {_age: 20};
Object.defineProperties(person, {
age: {
get: function() {
return this._age;
},
set: function(value) {
this._age = value;
person.updateBindings();
}
}
});
twoWayBind(person);
// later on
person.age = 40;
</script>
Hey, @straker, great gist!
I wrote a standalone extendable js-library inspired by it.
Please, check it out! 😃