Define text interpolation
A basic exmaple:
<div id="user"> {first} {last}</div>
var model = require('model-component')
var Reactive = require('reactive-lite')
var User = model('User')
.attr('first')
.attr('last')
var user = new User({
first: 'tobi',
last: 'blaz'
})
var el = document.getElementById('user')
var reactive = new Reactive(el, model)
model is a small library to make object emit events whenever an attribute is set.
After reactive
instance init, the element content would change instantly, and whenever you set first
or
last
attribute on model like user.first = 'john'
, the reactive would be noticed and change the view correspondingly.
You can have interpolation in text-node with silbings, like:
<div id="user"><span>First name is</span> {first} </div>
The reactivity only happens on text-node.
You can use function in interpolation, like:
<div id="user">fullname is {fullname()} {first} </div>
If you have fullname
function in the model:
user.fullname = function() {
return this.first + ',' + this.last
}
The function result will be rendered and the textContent would react the change of first
and last
attributes.
Notice that for performance and security, text interpolation use el.textContent
for rendering, you can use data-html
to render html, like:
<div data-html="description"></div>
The description
value of model would be set to el.innerHTML
.
If the output html is not just the attribute, you can use data-render for that, which gives you freedom to control model
and binding element
.
You can also make the binding reusable by create a binding
How does the interpolation works?
Reactive-lite would generate functions for each interpolation, for the interpolation {first}
,the function would be:
function (model) {
return model.first
}
For interpolation fulllname
, the function is:
function (model) {
return model.fullname()
}
The only thing have to do is prefix the attribute with model.
For the interpolation with filter like first | uppercase
, just wrap the result like:
function (model, filter) {
return filter.uppercase(model.first)
}
The logic of parsing reactive attributes from function is also quite simple, just find the function and toString()
, by
using a regex /\bthis\.([\w_$]+)\b(?!([\w$_]|\s*\())
, it can get all the attributes used by this.attribute
.
For the attribute used by the form this.['attribute']
, reactive would not be noticed.
Define attribute interpolation
Define attribute interpolation is the same like text interpolation, except that the real attribute would be set
without data-
prefix, eg:
<a data-href="https:/github.com/{name}/{repo}">link</a>
would be changed to something like:
<a href="https:/github.com/chemzqm/model">link</a>
The reason for the attribute transform is that interpolation on attribute in some browser would be consider invalid and
tripped the browser (eg: style
attribute on ie)
If there is no interpolation, the attribute would also be transformed with data-
prefix tripped
Here is the available data-attribute
list.
Use filter to format interpolation
You can use filter(s) to format the output in interpolation, eg:
<div id="user"> {first | uppercase}</div>
the textContent would be uppercase (like: 'TOBI') correspondingly
Another quite useful filter is nonull, if you don't want
undefinedor
null` to render on your page, you can:
<div id="user"> {first | nonull}</div>
If first
is undefined, the result would be an empty string.
Filters can be chained, eg:
<div id="user"> {first | uppercase | reverse}</div>
the result would be uppercase and then reversed.
Filter can have extra arguments, eg:
<div id="user"> {first | json 2}</div>
2
would be passed as number type and second arguments to json filter which defined like this:
exports.json = function (value, indent) {
return typeof value === 'string'
? value
: JSON.stringify(value, null, Number(indent) || 2)
}
Filters can also be used for attribute interpolation
The buildin filter list can be found here
Want to build your own filter? See Define your own filter
Use data-render for render other component
Assume that you have a nice looking count component, for count display:
<div data-render="renderCount"></div>
var model = new Model('Count').attr('total')
var count = new model({total: 100})
var Count = require('awesome-count')
var reactive = new Reactive(el, count, {
delegate: {
renderCount: function (model, el) {
var component = new Count(model.total)
el.appendChild(component.el)
}
}
})
The delegate config is used for holding the functions for data-render
and on-*event*
defined event handlers.
The data-render handler would accept corresponding model
and element
as arguments, and the context (this reference)
is preserved to delegate it self.
Without using of closure, the delegate function could be reused for higher level component (like list).