dom-data-bind
Tiny and supper simple way to bind data to DOM elements. Inspired by VueJS's templating system, which when combined with the Observables library, provide similar "auto-update-view-as-data-changes" functionality.
Install
$ npm install --save @purtuga/dom-data-bind
Usage
import {render, allDirectives} from "dom-data-bind"
const data = {
firstName: "Paul"
};
const div = document.createElement("div");
const divBinder = render(`<div>{{ firstName }}</div>`, data, allDirectives);
// Later....
data.firstName = "Tom";
divBinder.DomDataBind.setData(data);
// rendered DOM is no longer needed, stop its data watchers
// This is important in case your data is persisted beyond the life
// of the rendered element
divBinder.DomDataBind.destroy();
As a HTML drop-in
<script type="module">
import {render} from "//unpkg.com/@purtuga/dom-data-bind?module";
var binder = render(`<div>hello {{name}}!</div>`, { name: "paul" });
document.body.appendChild(binder);
</script>
render()
render(htmlTemplate, data, directives) {
// returns DocumentFragment
}
The render()
function will return a DocumentFragment
with the given HTML template provided on input bound the the data provided. A list of directives should also be defined if your template uses any Directive outside of the Token interpolation.
IMPORTANT: When defining an array of directives, the order in which the directives are in (the
array
) is important. Any directive that manages the DOM elemnet should be at the beginning of the arrary. Example: by default, theEach
andIf
directives are the begning of theallDirectives
array (positions0
and1
respectively).
Template Token Interpolation
Tokens are defined using the double mustache (curly braces): {{ }}
. These will be evaluated within the context of the data
provided on input.
Directives
All directives start with the underscore character (_
). Example:
<div _if="visible" _on.click="sayHello">{{ label.clickme }}</div>
_if
Usage:
<div _if="showDiv">...</div>
Conditionally render an element and it's bindings based on the truthy
of an expression.
Note: in order to hide these types of conditional elements on initial page rendering, the following CSS rule should be added to you page stylesheet:
[_if] { display: none; }
_show
Usage:
<div _show="isVisible">...</div>
Conditionally show or hide an element (uses style.display
). Unlike _if
, this directive will process the element's children.
Note: in order to hide these types of conditional elements on initial page rendering, the following CSS rule should be added to you page stylesheet:
[_show] { display: none; }
_class
Usage:
<div _class="{ 'make-element-red': transaction.atError }">...</div>
Conditionally toggle css class names on an element. Class names are defined in an object as the key
and it will be applied if the value of that key evaluates to truthy
and removed if it evaluates to falsey
.
_style
Usage:
<div _style="{ 'background-color': divStyles.bgcolor }">...</div>
Similar to _class
but with element styles directly (style
attribute. Conditionally toggle css styles on an element.
_attr.{attr}
Usage:
<div _attr.title="page1.title">...</div>
Bind a value to an Element's attribute. The attribute name is defined by using a period followed by the attribute name.
_on.{event}
Usage:
<a _on.click="doClick">...</a>
<!-- or: just evaluate an expression -->
<a _on.click="isDone ? runClick($ev) : validateClick($ev)"></a>
Bind a function to a event or evaluate an expression. When evaluating an expression, the DOM event object is available as $ev
.
_each
Usage:
<!-- Arrays -->
<div _each="item in itemsArray">{{ item }}</div>
<div _each="(item, index) in itemsArray">...</div>
<!-- Objects -->
<div _each="value in itemsObject" _key="value.id">{{ value.name }}</div>
<div _each="(value, key) in itemsObject">...</div>
Loop through a list using the HTML element as the template for each item.
For efficiency, each template item should have a unique id that can be used with the _key
directive. Expressions inside of an each
template can access parent context using $parent
or the $root
to access the root data.
Note: in order to hide these types of conditional elements on initial page rendering, the following CSS rule should be added to you page stylesheet:
[_each] { display: none; }
_html
Usage:
<div _html="ele.markup"></div>
Bind HTML markup to the elements (sets its innerHTML
). WARNING: Inserting markup directly into the page can be dangerous and lead to XSS attacks.
DomDataBindElement
)
Custom Element Constructor (A Custom Element constructor (base class) - src/DomDataBindElement.js
- is also provided which uses @purtuga/component-element
. This base class is not exported nor is it included in the built bundle, and must be import
'd explicitly in order to be used. @purtuga/component-element
must first be installed - installation of his library will not install it automatically.
The DomDataBindElement
will contain an instance member called state
which should be set component is Mounted and which changes automatically trigger a render lifecycle to be scheduled.
Install
Ensure @purtuga/component-element
is installed
npm i @purtuga/component-element --save
Example
import {DomDataBindElement} from "dom-data-bind/src/DomDataBindElement"
class MyEle extends DomDataBindElement {
didMount() {
this.state = {
msg: "Hello World"
}
}
render() {
return `<div>{{state.msg}}</div>`;
}
}