domr
Update DOM element content/attributes asynchronously.
Heavily inspired by Ampersand.js DOM
bindings but without
needing inheritance and wrapping your data into Models/State
objects.
"inheritance is the root of all evil" - Albert Einstein :P
Important: I will only test on modern browsers, use at your own risk.
Why?
Couldn't find anything that was fast on a slow mobile device and worked the way I wanted, so let's reinvent the wheel. See this twitter thread for more details.
I know there are hundreds of JS frameworks out there and that data binding is the coolest thing since sliced bread, but this will probably work better for my use case (low memory, slow cpu, few updates and usually async - usually in batches).
This approach allows you to write the markup and build the DOM any way you want (eg. web components, any template language or just plain HTML).
Example
given this HTML fragment:
You can update it with:
var domr = ;var el = document; // this will create a mapping between properties and elements/actionsvar foo = domr; // this will update the DOM asynchronouslyfoo; // called after data is updated (on next animation frame) { console;}
The document will be updated on the next requestAnimationFrame
, becoming:
Wow, Such Awesome wow. much javascript. such ipsum
If you call render
multiple times in a row with different data, it should
only update the DOM once. DOM manipulation is batched and throttled, and always
happens on a requestAnimationFrame
.
Subsequent calls to render
should be faster since we cache references to
all the needed elements on the first call. We also check which data changed
since last render and only update the affected elements/attributes.
When you don't need the binding anymore you can call destroy
to remove any
references to elements and cached data (not needed on most cases tho).
// remove internal cache and references to elementsfoo;
Tips
This lib is not only about raw performance, a great benefit is that you can
keep calling render
even if the data did not change and it is smart enough to
only update the affected elements. This simplifies the development process and
reduces the amount of conditionals in the codebase.
It's similar to the way React works, in the sense that we always render but only it's smart enough to only update the DOM when needed. The main difference is that we don't have a virtual DOM and we also don't handle how the state/data is passed into the views (meaning that we save thousands of lines of code on the library side but you might need to implement more logic yourself).
Binding types
Bindings treats undefined
, null
, and NaN
as ''
(empty string).
text
Sets textContent
of selected element.
'model.key': type: 'text' selector: '.someSelector' // or role
class
Sets class as string that matches value of property. It can handle multiple classes (single string separated by spaces) and will also remove previous class if value is updated.
'model.key': type: 'class' selector: '.someSelector' // or role
attribute / attr
Sets the whole attribute to match value of property.
'model.key': type: 'attribute' // or "attr" selector: '#something' // or role name: 'width'
toggleClass
Add/removes class based on boolean interpretation of property name.
'model.active': type: 'toggleClass' selector: '#something' // or role // to specify name of class to toggle (if different than key name) // you could either specify a name name: 'active' // or a yes/no case yes: 'active' no: 'not-active'
toggleAttribute / toggleAttr
Toggles whole attribute on the element (think checked
) based on boolean interpretation of property name.
'model.isAwesome': type: 'toggleAttribute' // or "toggleAttr" selector: '#something' // or role name: 'checked'
html
Renders innerHTML
based on property value.
PS: this won't escape any HTML entities and can be used as an attack vector
(XSS), favor
the text
type as much as possible.
'model.key': type: 'html' selector: '#something' // or role
Handling multiple bindings for a given key
If given an array, then treat each contained item as separate binding
'key': type: 'toggleClass' selector: '#something' // or role name: 'active' // (optional) name of class to toggle if different than key name type: 'attr' selector: '#something' // or role name: 'width'
Install
Modules are converted to node.js format during npm publish in case you want to use it with browserify.
npm install domr
or you can use the something like volo to download the
AMD source files. (or just use the files inside src
)
volo add millermedeiros/domr#src domr
License
Released under the MIT license.