Declarative data binding
liaison's declarative data binding is based on <template>
element, one of the specs in Web Components umbrella.
<template>
element creates an inert DOM tree based on its content. liaison adds two-way data binding feature to <template>
, which can be used by loading liaison/DOMTreeBindingTarget module and then calling HTMLTemplateElement#bind()
API.
HTMLTemplateElement#bind()
API creates one or multiple copies (called "instances") of <template>
's DOM tree, and can be used in one of the following ways:
- To create a single instance based on data model:
HTMLTemplateElement#bind("bind", observable)
- To create repeating instances based on an array of data model:
HTMLTemplateElement#bind("repeat", observableArray)
Let's take a look at the first one. If you have <template>
like below:
You can instantiate it by assigning a data model by below code for example:
You can do the repeating one in a similar manner:
Note: wrapper.wrap()
API creates a tree of "container object", called Observable
and ObservableArray
. "Container object" approach allows event-driven change noitification instead of dirty-checking, which ensures the best performance especially for large-scale applications with many watched objects. In environment where ES7 Object.observe()
and Array.observe()
are available natively, liaison's two-way data binding features work with plain JavaScript object/array.
<template>
content is instantiated as siblings of <template>
. Here's the (explanatory) state of DOM after repeating template instances are created (2nd example):
<template id="my-template">
<div>
First: <input type="text" value="{{first}}">
Last: <input type="text" value="{{last}}">
</div>
</template>
<div>
First: <input type="text" value="Anne">
Last: <input type="text" value="Ackerman">
</div>
<div>
First: <input type="text" value="Ben">
Last: <input type="text" value="Beckham">
</div>
<div>
First: <input type="text" value="Chad">
Last: <input type="text" value="Chapman">
</div>
<div>
First: <input type="text" value="Irene">
Last: <input type="text" value="Ira">
</div>
Nested template
<template>
can be nested with <template bind="{{observable}}">
and/or <template repeat="{{observableArray}}">
syntaxes, which correspond to template.bind("bind", observable)
and template.bind("repeat", observableArray)
respectively. For example, you can do:
Two-way data binding
liaison's data binding is two-way in many cases. With two-way binding, change in data model is reflected to UI, and change in UI is reflected back to model. In below example, change in <input>
automatically updates data model. Update in data model automatically updates the text underneath:
See here to see in what cases two-way binding is supported.
In addition to two-way data binding between model property and UI, repeating template instances reflects array splices in model:
Updating array element with particular index (e.g. model.set(1, wrapper.wrap({first: "John", last: "Jacklin"}))
) as well as push()
/pop()
, etc. are translated to splices and are reflected to repeating template instances.
More ways to work with template
liaison's declarative data binding provides more ways to work with <template>
. See here for details.