Monkberry templates allow to write ui in mustache-like syntax with conditions, loops and expressions, which will then be compiled to efficient JavaScript code.
Monkberry perceives everything inside {{
and }}
mustache as JavaScript expression.
<div class="greetings {{ visible ? '' : 'hidden' }}">
Hello, {{ user.name + "!" }}
</div>
Monkberry provides XSS protection by default, so you don’t need to worry about it.
In attributes you can use expressions with {{
and }}
.
<div class="foo {{ bar }}">
If your attribute contains only one expression you can omit "
and "
:
<div class={{ baz }}>
Can be any valid JavaScrpt expressions.
{% if count < 0 || count > 10 %}
...
{% else %}
...
{% endif %}
Any number of variables in if
:
{% if array.indexOf(search) != -1 %}
...
{% endif %}
Note that Monkberry updates only one of
if
,else
block.{% if cond %} Then {{ value }}! {% else %} Else {{ value }}! {% endif %}
Render that template:
const view = Monkberry.render(Template, document.body); view.update({ cond: true, value: 'one' });
View will be
Then one!
. Then if we update view:view.update({ cond: false, value: 'two' });
View will be
Else two!
. But if we now update onlycond
, variable of “then” part will be same as before.view.update({ cond: true });
View will be
Then one!
(instead ofThen two!
).This happens because Monkberry doesn’t store variables passed to
update
function, it stores only DOM nodes. Monkberry will update only one part ofif
,else
.
Monkberry can loop over arrays and objects as well.
{% for array %}
{{ name }}
{% endfor %}
In this form, the body of for
has access only to variables which for
is iterating on.
view.update({
array: [
{name: 'Monkberry'},
...
]
});
To access outer scope specify iterator name.
{% for user of array %}
{{ user.name }}
{% endfor %}
Also key can be specified.
{% for key, user of array %}
{{ key }}: {{ user.name }}
{% endfor %}
The view rendering process consists of two phases: first we create the node and then we update the node content with data.
Sometimes the data for the view is not available at the time of rendering, and we have to specify default values.
The best way to do it is to use logical OR operator ||
.
<div class="foo {{ modify || 'baz' }}">
{{ content || "No content" }}
</div>
In this case on template render the view will be filled with default data:
<div class="foo baz">
No content
</div>
Note that if you use any variable on the right side of OR operator, that can’t be used as default data.
{{ content || "No content" + foo }}
Any expression support filter statement.
Hello, {{ user.name | upper }}
To define that filter:
import Template from './template.monk';
const filters = {
upper: (text) => text.toUpperCase()
};
const view = Monkberry.render(Template, document.body, {filters});
Also Monkberry understands parameters for filters:
const filters = {
replace: (text, from, to) => text.replace(from, to)
};
{{ text | replace(/.../, '$1') }}
And allows to combine filters:
{{ text | lower | replace(/.../, '$1') | upper }}
That expression will be compiled into following JavaScript:
upper(replace(lower(text), /.../, '$1'));
Filters can be used in expressions, if
and for
statements.
Describe custom tag in separate template, for example todo.monk
:
<div>
{% if complete %}
<s>{{ text }}</s>
{% else %}
<em>{{ text }}</em>
{% endif %}
</div>
and then import and use it in another template:
{% import Todo from 'todo.monk' %}
<Todo complete={{ complete }} text={{ text }}/>
<Todo complete={{ true }} text="with static text"/>
<Todo {{ ...todo }}/>
Spread attributes allow to easily convert object into node attributes.
The properties of the object that you pass in are copied onto the node’s attributes.
<input {{...attr}}/>
const view = Monkberry.render(Template, document.body);
view.update({
attr: {
id: 'foo',
value: 'baz'
}
});
You can combine it with other attributes.
<input {{...attr}} value={{ value }}/>
Note that later updates of attributes override previous ones.
view.update({value: 'baz'});
// ...
view.update({attr: {value: 'new baz'}}); // Will override previous value.
Spread operator also works well with custom attributes. In fact, this is the best way to pass data into custom tag.
<CustomTag {{...attr}}/>
It is possible to import anything in template: files, modules and another templates.
Custom tags:
{% import CustomTag from './CustomTag.monk' %}
<CustomTag/>
Imported functions can be used as functions:
{% import upperCase from 'upper-case' %}
<input value={{ upperCase(value) }}>
Imported functions can be used as filters as well:
{% import upperCase from 'upper-case' %}
<input value={{ value | upperCase }}>
Monkberry escapes all inserted variables by default. But if you want to insert
some HTML template via variable you can use unsafe statement which is using innerHTML
.
Improper use of the unsafe statement can open you up to a cross-site scripting (XSS) attack.
{% unsafe '<a href="XSS">...</a>' %}
{% unsafe html %}
You can use standard html comments.
<!-- Comment does here -->
Comments will be cut out from template.
In next chapter we describe how to use event handling with Monkberry.