Skip to content

Instantly share code, notes, and snippets.

@plugnburn
Last active January 31, 2023 15:02
Show Gist options
  • Save plugnburn/f9d3acf33bee8f3f7e2d to your computer and use it in GitHub Desktop.
Save plugnburn/f9d3acf33bee8f3f7e2d to your computer and use it in GitHub Desktop.
DaBi - live two-way DOM-to-data binding in 25 lines of JS

DaBi: data binding library that keeps it simple

DaBi (short for Data Binding) is a dead simple yet complete and self-contained DOM-to-JS and JS-to-DOM data binding library in just 25 lines of pure ES5 and 454 bytes when minified.

How to obtain

Download it right here or include it into your HTML:

<script src="//cdn.rawgit.com/plugnburn/f9d3acf33bee8f3f7e2d/raw/50d2148811f8da61d70cdceec83ecbde5e484b83/dabi.min.js"></script>

Usage

Unlike most similar libraries, DaBi operates neither on data- attributes nor on single DOM elements. It operates on selectors, thus is able to robustly handle element lists that change over time.

You bind a property of an object to the selector with a single DaBi(selector, object, property[, isEnumerable = false]) call, and that's all you really need. For example:

var myContent = {}
DaBi('p.main', myContent, 'mainParagraph') // data-to-DOM binding example
DaBi('input.new', myContent, 'newContent', true) // DOM-to-data binding example with enumeration enabled

That's it. Whenever you modify myContent.mainParagraph property, a <p> element with main class will be populated with its content. And whenever you input something into a text field with new class, the myContent.newContent JS property will be set accordingly to the first matching element value. In addition, you can enable enumerating the value with standard ways (for .. in, Object.keys etc) by setting the fourth argument, isEnumerable, to true.

Actually, all bound DOM values are read on demand, so they will always reflect actual DOM data state.

Browser support

Should run perfectly on any ES5-compliant browser.

!function(){
function xval(sel, val, l, i) {
for(l=document.querySelectorAll(sel),i=0;el=l[i++];) {
if(val==null)
return 'value' in el ? el.value : el.innerHTML
else if('value' in el) {
el.value = val
if (el.tagName.toLowerCase()==='select')
Array.prototype.forEach.call(el.querySelectorAll('option'), function(opt) {
opt.selected = (opt.value == val)
})
}
else el.innerHTML = val
}
}
window.DaBi = function(sel, obj, prop, isEnum) {
Object.defineProperty(obj, prop, {
get: function(){return xval(sel)},
set: function(v){xval(sel, v)},
configurable: true,
enumerable: !!isEnum
})
}
}()
!function(){function e(b,a,c,d){c=document.querySelectorAll(b);for(d=0;el=c[d++];){if(null==a)return"value"in el?el.value:el.innerHTML;"value"in el?(el.value=a,"select"===el.tagName.toLowerCase()&&Array.prototype.forEach.call(el.querySelectorAll("option"),function(b){b.selected=b.value==a})):el.innerHTML=a}}window.DaBi=function(b,a,c,d){Object.defineProperty(a,c,{get:function(){return e(b)},set:function(a){e(b,a)},configurable:!0,enumerable:!!d})}}()
@GrosSacASac
Copy link

Why not take advantage of .textContent instead of innerHTML ?

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment