Barbiche is available as a npm package:
npm install barbiche
For decent browser support, using some polyfills is required. Good results can be obtained with:
- template (available as npm package template-mb)
- classList.js (available as npm package classlist.js, only needed for IE9 support)
The polyfills are included in Barbiche package in polyfills.min.js
:
- version 3.x of Barbiche contains template-mb
- version 2.x of Barbiche contains template-mb and classList.js
First, we create a Barbiche instance:
var barbiche = Barbiche();
Now, barbiche
is a factory function that expects the id string of a <template>
element or a <template>
element:
barbiche('my-template');
// or
barbiche(document.querySelector('#my-template'));
If no template is found, an unnamed empty <template>
element is used so that subsequent operations fail silently.
If the template has an id attribute, Barbiche internally stores the template for later reuse:
var inst1 = barbiche('my-template');
var inst2 = barbiche('my-template');
// inst1 === inst2
Setting ids on your templates is strongly recommended.
Merging data into a Barbiche instance is done in this way:
var frag = barbiche('my-template').merge(obj_k,..., obj_3, obj_2, obj_1);
The arguments of merge
method are used to init the merge context: when Barbiche is looking for the value of an identifier, it searches first in obj_1
, then in obj_2
,..., then in obj_k
. For example, you may consider that:
obj_1
is a plain JSON object that comes from your databaseobj_2
is an object that contains functions and data specific tomy-template
obj_3
is an object that contains functions and data common to all your templates
Some examples can be found here.
A DocumentFragment is returned that can be inserted in the main document:
document.body.appendChild(frag);
When you are done with your merge operations, you can clean the barbiche
store:
barbiche.clean('my-template');
//or
barbiche.clean(); // clear all registered templates
Barbiche instances expose a factory function for BBObj class:
var bbObj = barbiche.bbObj;
var bbObjInstance = bbObj(value, name);
Barbiche objects can be used to create a template from a string with an optional id:
var id = 'my-template';
var str = '<div><span>{{text}}</span></div>';
barbiche(bbObj(str, id));
//or
barbiche(bbObj(str));
Barbiche instance constructor accepts an optional settings object which defaults to:
Barbiche({
delimiters: ['{', '}'],
prefix: 'bb-',
document: document,
destructive: true
});
delimiters
is an array containing two distinct one character strings that will be used as delimiters for text and HTML insertion. Note that backslash character (\
) is used for escaping delimiters and cannot be used as a delimiter. Some examples can be found here.prefix
is the word used to prefix Barbiche attributes. Internally, Barbiche uses the following attributes:bb-[if|else|alias|text|html|repeat|import|attr|class|global|inert]
. If you need to use one of these attributes, you can set Barbiche prefix according to your needs.document
is the HTML document where Barbiche will search for templates.destructive
is a boolean that allows Barbiche to modify the HTML of the registered templates. (If false, Barbiche will use deep clones of the templates leaving your HTML untouched.)
Barbiche heavily relies on the great properties of the <template>
element. An essential point of Barbiche is that you can wrap any html fragment of the template in a <template>
element without changing the merge result. Sooner or later, you will want to set a Barbiche attribute between an element and its parent: just wrap the element in a <template>
tag and set the attribute on this new tag.
Barbiche templates are decorated with special attributes which are evaluated in this order:
bb-if="expression"
(andbb-else
)bb-alias="expression"
bb-repeat="expression (++|--)?"
bb-import="expression"
bb-attr="expression"
bb-class="expression"
and use {{expression}}
and {{{expression}}}
for merging text and HTML, respectively.
An additional attribute bb-inert
can be set on a <template>
element so that Barbiche will consider it as any other non <template>
element.
Barbiche expressions support a subset of JavaScript:
- boolean expressions:
true
,false
,||
,&&
,==
,!=
,===
,!==
,<=
,>=
,<
,>
and!
- null and undefined keywords:
null
andundefined
- identifiers:
my_text
,my_html
- arrays:
[]
,[text, "string", 1.12]
- function calls:
my_function(obj)
,JSON.stringify(JSON.parse(str))
- property accessors:
object.property
andobject[computed property]
- simple numbers:
1.2
,5
,-7.58
- strings:
"double\"quote\"string"
and'simple\'quote\'string'
+
operator
and a special constructor: expression: expression
for building Barbiche object.
For convenience, any string can be used as an identifier by using backtick delimiters: `this-is not-a-valid-JS-identifier`
.
Backticks inside a backticked identifier have to be escaped: \`
.
Strings and identifiers support usual escape sequences (\n|\t|\r|\\|\'|\")
, hexadecimal and unicode escape sequences. Examples can be found here.
Inserting text is done with {{expression}}
.
- if
expression
is a Barbiche objectboolean: content
, ifboolean
is true and ifcontent
is notnull
orundefined
, a text node containingcontent.toString()
is inserted - else, if
expression
is notnull
orundefined
, a text node containingexpression.toString()
is inserted
A simple example:
<template id="text">
<div>{{text}}</div>
</template>
barbiche('text').merge({
text: "This is some text."
});
will produce:
<div>This is some text.</div>
Other examples can be found here.
Inserting HTML is done with {{{expression}}}
.
- if
expression
is an instance ofNode
, it is inserted - else if
expression
is a Barbiche objectboolean: content
, ifboolean
is true and ifcontent
is notnull
orundefined
,content.toString()
is inserted as HTML - else, if
expression
is notnull
orundefined
,expression.toString()
is inserted as HTML
A simple example:
<template id="html">
<div>{{{html}}}</div>
</template>
barbiche('html').merge({
html: "<p>This is some<strong>html</strong>.</p>"
});
will produce:
<div><p>This is some<strong>html</strong>.</p></div>
Other examples can be found here.
if an element is decorated with a bb-if="expression"
attribute, its next sibling element (if it exists) may be decorated with an (empty) bb-else
attribute. According to the truth value of expression
, the element or its next sibling element is removed.
Note that no curly braces expression can be set between two consecutive sibling elements decorated with bb-if
and bb-else
and that a node cannot be decorated with both bb-if
and bb-else
attributes.
A simple example:
<template id="condition">
<div bb-if="bool1">TRUE</div>
<div bb-else>FALSE</div>
<div bb-if="bool2">TRUE</div>
<div bb-else>FALSE</div>
</template>
barbiche('condition').merge({
bool1: true,
bool2: false
});
will produce:
<div>TRUE</div>
<div>FALSE</div>
Other examples can be found here.
A bb-alias
contains a Barbiche object or an array of Barbiche objects. For each object value: name
, name
is bound to value
during the processing of the current subtree.
A simple example:
<template id="alias">
<div bb-alias="value: 'alias'">{{alias}}</div>
</template>
barbiche('alias').merge({
value: 5
});
will produce:
<div>5</div>
Other examples can be found here.
A bb-repeat
attribute contains an expression and ends with an optional --
or ++
keyword. The expression denotes a Barbiche object or an array of Barbiche objects which defines a set of nested loops. For each Barbiche object array: 'string'
, a loop is executed on array
, binding each array item to 'string'
and item index to '_string_'
. A ++
ending keyword will insert merged items in natural order; --
will insert merged items in reverse order; no ending keyword is the same as ++
.
For convenience, an undefined
or null
value for array
is interpreted as an empty array: []
.
Any object with a forEach
method (e.g. Maps or Sets) can be used in loops.
A simple example:
<template id="loop">
<div>
<span bb-repeat="items: 'item'">{{item.name}} ({{_item_}})</span>
</div>
</template>
barbiche('loop').merge({
items: [
{species: "hen", name: "Elsa", show: true},
{species: "cat", name: "Jacynthe", show: false},
{species: null, name: "Zaza", show: true}
]
});
will produce:
<div>
<span>Elsa (0)</span>
<span>Jacynthe (1)</span>
<span>Zaza (2)</span>
</div>
Other examples can be found here.
The bb-import
attribute is reserved to <template>
elements. The value of a bb-import
attribute can be a template node, a template id or a Barbiche object. It is applied to the barbiche instance function. The returned template is then merged using current context and the current node is replaced with the merge result.
A simple example:
<template id="simple-subtemplate">
<div>
<template bb-import="'sub'"></template>
</div>
</template>
<template id="sub">
<span>I am a subtemplate!</span>
</template>
barbiche('simple-subtemplate').merge();
will produce:
<div>
<span>I am a subtemplate!</span>
</div>
Other examples can be found here.
A bb-attr
attribute contains a Barbiche object or an array of Barbiche objects. For each object value: name
, if value
and name
are not undefined
or null
and if name.toString()
is not empty, attribute name.toString()
is set on the current node with value value
.
A simple example:
<template id="attribute">
<div bb-attr="value: 'my-attr'"></div>
</template>
barbiche('attribute').merge({
value: 'my-value'
});
will produce:
<div my-attr="my-value"></div>
Other examples can be found here.
A bb-class
attribute contains an expression or an array of expressions. For each expression:
- if expression is a Barbiche object
boolean: name
, ifboolean
is true and ifname
is notnull
orundefined
and ifname.toString()
is not empty, classname.toString()
is added to the current element, - else if
expression
is notnull
orundefined
and ifexpression.toString()
is not empty, classexpression.toString()
is added to the current element.
A simple example:
<template id="class">
<div class="item" bb-class="myClass"></div>
</template>
barbiche('class').merge({
myClass: 'my-class'
});
will produce:
<div class="item my-class"></div>
Other examples can be found here.
A bb-inert
attribute can be set on a <template>
element so that Barbiche will consider the element as any other non <template>
element.
Note that a <template>
element can not be decorated with both bb-inert
and bb-import
attributes.
A simple example:
<template id="inert">
<template><p>Not inert template</p></template>
<template bb-inert><p>Inert template</p></template>
</template>
barbiche('inert').merge();
will produce:
<p>Not inert template</p>
<template><p>Inert template</p></template>
Other examples can be found here.
Templates included in subdocuments (such as HTMLImports) need to be bootstrapped before being usable by calling:
if (window.HTMLTemplateElement.bootstrap) window.HTMLTemplateElement.bootstrap(otherDoc);
Polyfilled templates are not as inert as native templates. For examples, scripts will be executed and images will be loaded.
In some rare situations, the HTML parser may break the template content. For example:
<template id="table-fragment">
<tr>
<td>a</td><td>b</td>
</tr>
</template>
will give you an empty template. A workaround for this is to use a <script>
tag:
<script id="table-fragment" type="text/barbiche-template">
<tr>
<td>a</td><td>b</td>
</tr>
</script>
and then register the template with:
var script = document.querySelector('#table-fragment');
var bbObj = barbiche.bbObj;
barbiche(bbObj(script.text, script.id));