The constructor window.TT is an HTML template processor written in javascript
that implements two-way
data binding.
element
A DOM
element. The content of the element is will be processed
model
A
javascript object that will serve as a model for our template
options
Here you can set statements names, interpolation regex and templates
a tt object. The most important method is set
<div id=example>${data}</div>
<script>
new TT(document.getElementById("example"),{data:"some data"},{ // here the default values
interpolation : /\$\{([\s\S]+?)\}/,
ifAttr : "if",
foreachAttr : "foreach",
foreachKeyNameAttr : "foreachKeyName",
bindAttr : "bind",
bindDOMPropAttr : "bindDomProp",
bindEventsAttr : "bindEvents",
setTemplateAttr : "set",
useTemplateAttr : "use",
useTemplateParamsAttr : "params",
isolateAttribute : "isolate",
srcAttribute : "src"
});
</script>
Interpolation allows to define node texts and attributes values and names ( when setting attributes names, remember that it will changed to lowercase ).
<div id="example">
<a href="${URL}" ${hidden}>${text}</a>
</div>
<button onclick="changeHidden()">Change hidden value</button>
<script>
let model = {
URL : "https://github.com/tilepieces",
text : "some text",
hidden : "hidden"
};
let template = new TT(document.getElementById("example"),model);
function changeHidden(){
template.set("hidden",model.hidden ? "" : "hidden");
}
</script>
See the live example
Statements are defined by data attributes
tells the parser to render or not ( the dom element
will be removed ) a tag.
The attribute value is a variable that will be coerced to a boolean.
<div id=example>
<div data-if="show">This will be shown</div>
<div data-if="hide">This will be hidden</div>
</div>
<button id="toggle-visibility">Toggle visibility</button>
<script src="../tt.js" data-tilepieces-component="tt"></script>
<script>
let scope = {
show:true,
hide:false
};
let template = new TT(document.getElementById("example"),scope);
document.getElementById("toggle-visibility").onclick = ()=>{
scope.show = !scope.show;
scope.hide = !scope.hide;
template.set("",scope);
};
</script>
See the live example
Tells the parser to render a tag n-times according to
an array of objects.
You can retrieve object property using key or setting the data-foreach-key-name attribute in
the same tag ( best for nested arrays ).
<ul>
<li data-foreach="array1">
<div>Name <span>${key.name}</span></div>
<div>Value <span>${key.value}</span></div>
</li>
</ul>
<ul>
<li data-foreach="array2" data-foreach-key-name="prop">
<div>Name <span>${prop.name}</span></div>
<div>Value <span>${prop.value}</span></div>
<ul>
<li data-foreach="prop.array" data-foreach-key-name="propNested">
<div>Name <span>${propNested.name}</span></div>
<div>Value <span>${propNested.value}</span></div>
</li>
</ul>
</li>
</ul>
<script>
let array1 = [{
name: "array1_1",
value: 10
},
{
name: "array1_2",
value: 100
}];
let array2 = [{
name: "array2_1",
value: 0,
array : [{
name: "array2_1_0_nested",
value: 0
}]
},
{
name: "array2_2",
value: 10,
array : [{
name: "array2_2_0_nested",
value: 1
},{
name: "array2_2_0_nested",
value: 2
}]
}]
let scope = {array1, array2};
let template = new TT(document.body,scope);
</script>
See the live example
Allows you to link the data model to user changes
through the input, select, textarea tags and with the
contenteditable attribute. By default it is linked with the change event, but you can override this
behavior by defining the data-bind-events tag (which accepts multiple values separated by a comma).
<section>
<input placeholder="name"
data-bind="user.name"
data-bind-events="input">
<input placeholder="surname"
data-bind="user.surname"
data-bind-events="input">
<fieldset>
Male<input type="radio" data-bind="user.sex" name="user.sex" value="M"><br>
Female<input type="radio" data-bind="user.sex" name="user.sex" value="F">
</fieldset>
<fieldset>
<input type="checkbox" data-bind="user.employed">
</fieldset>
<fieldset data-if="user.employed">
<select data-bind="user.job">
<option value="developer">developer</option>
<option value="designer">designer</option>
<option value="manager">manager</option>
<option value="hr">hr</option>
<option value="other">other</option>
</select>
</fieldset>
<h1 data-if="!user.name && !user.surname">Please fill inputs</h1>
<h1 data-if="user.name || user.surname">
Hello ${user.name} ${user.surname}!</h1>
<pre>
</pre>
</section>
<script>
let scope = {
user : {
name : "",
surname : "",
sex:"M",
employed : true,
job : "developer"
}
};
let section = document.querySelector("section");
let template = new TT(section,scope);
let pre = document.querySelector("pre");
section.addEventListener("user.name",e=>{
console.log("user.name detail ->", e.detail)
})
section.addEventListener("user.surname",e=>{
console.log("user.surname detail ->", e.detail)
})
section.addEventListener("template-digest",e=>{
console.log("template-digest ->", e.detail)
pre.innerHTML = JSON.stringify(scope,null,4);
});
</script>
See the live example
Attach a variable as a property of a DOM element
<div onclick="alertData(this)" data-bind-dom-prop="__data,data" style="cursor:pointer">Click here for an alert with the data value</div>
<input data-bind="data" placeholder="change data here">
<script>
var scope = {data:""};
var template = new TT(document.body,scope);
function alertData(el) {
console.log(el);
alert(el.__data);
};
</script>
See the live example
Bind an HTML template ( that could be defined through
data-set or in the options values ) to a tag.
data-params is used pass variables using another name.
Example using data-set ( See the live example )
<section>
<div data-set="test-template">
<span>${obj.name}</span>:
<span>${obj.value}</span>
</div>
<ul>
<li data-foreach="data"
data-use="test-template"
data-params="obj,key"></li>
</ul>
</section>
<script>
let scope = {
data : [{
name : "name1",
value : "value1"
},{
name : "name2",
value : "value2"
}]
}
let el = document.body.children[0];
let t = new TT(el,scope);
</script>
Example using the template tag ( See the live example )
<section>
<ul>
<li data-foreach="data"
data-use="test-template"
data-params="obj,key"></li>
</ul>
</section>
<template id="test-template">
<span>${obj.name}</span>:
<span>${obj.value}</span>
</template>
<script>
let scope = {
data : [{
name : "name1",
value : "value1"
},{
name : "name2",
value : "value2"
},{
name : "name3",
value : "value3"
}]
};
let template = document.getElementById("test-template");
let el = document.body.children[0];
let t = new TT(el,scope,{
templates : [{
name : "test-template",
el : template.content
}]
});
</script>
Used in frame and img tags
to dynamically set them without letting the browser download template placeholders
( See the live example )
Isolate part of the HTML. This part will not be processed.
<section>
<div>
<span>${name}</span>:
<span>${value}</span>
</div>
<div data-isolate>
<div>This element is isolated:</div>
<span>${name}</span>:
<span>${value}</span>
</div>
</section>
<script>
let scope = {
name : "an",
value : "example"
}
let el = document.body.children[0];
let t = new TT(el,scope);
</script>
See the live example
The set method allows to update the
model. You can pass the property to be changed as a string (the original object will also be updated), but if you need
to make more than one change it is better to pass the whole object.
<section>
${name}<br>
${nestedExample.name}
<ul>
<li data-foreach="array">
${key.name}
</li>
</ul>
</section>
<script>
let scope = {
name : "an example",
nestedExample : {
name : "an example2"
},
array : [
{name : "an example3"}
]
}
let el = document.body.children[0];
let t = new TT(el,scope);
let o = "an example changed";
t.set("name",o);
console.assert(scope.name == o);
let o2 = "an example2 changed";
t.set("nestedExample.name",o2);
console.assert(scope.nestedExample.name == o2);
let o3 = "an example3 changed";
t.set("array[0].name",o3);
console.assert(scope.array[0].name == o3);
</script>
See the live example