Directives - View Working Example
Directives are properties in the stache attribute that require special handling. Directives are in the format "{directive}". The following directives are supported:
- {if} - the element is rendered or removed based on the model value associated with the "if" directive
- {root}- process element children using a specified root data object.
- {oninit} - the associated function is called after the element has been processed
- {template} - specifies a document fragment to use for an array element
- {base} - Used to refer to the original object used to fill. Eg. {}="textContent:{base}.message"
{if}
The following example demonstrates the use of the {if} directive. Only the second div is shown. This directive is not reactive, so the affected DOM is removed permanently.
HTML
<div id="ifExample">
<div {}="{if}:hidden">You should not see me</div>
<div {}="{if}:shown">You should be able to see me</div>
</div>
Javascript
let ifModel = {
hidden: false,
shown: true
};
_M_.fill(document.getElementById('ifExample'), ifModel);
{root}
The {root} directive modifies the context root to the specified object for all child elements. In this example, the stache element is setup both with and without the root directive. They are equivalent, but using root reduces the amount of markup needed.
HTML
<div id="rootExample">
<div style="margin-bottom:10px;">Contact information without {root} directive</div>
<div>
Name: <span {}="contact.name"></span><br />
Address: <span {}="contact.address"></span><br />
City: <span {}="contact.city"></span>, State: <span {}="contact.state"></span> Zipcode: <span {}="contact.zipcode"></span>
</div>
<div style="margin-top:10px;margin-bottom:10px;">Contact information with {root} directive</div>
<div {}="{root}:contact">
Name: <span {}="name"></span><br />
Address: <span {}="address"></span><br />
City: <span {}="city"></span>, State: <span {}="state"></span> Zipcode: <span {}="zipcode"></span>
</div>
</div>
Javascript
let rootModel = {
contact: {
name: 'Jim',
address: '1234 Main',
city: 'New York City',
state: 'NY',
zipcode: '81000'
}
};
_M_.fill(document.getElementById('rootExample'), rootModel);
{oninit}
The {oninit} directive specifies a function to call after an element has been filled. You can also call a function without assigning to the element by specifying the colon ":" first. This method differs from the oninit directive in that it can be called before the element is filled.
This example adds "(initialized)" after the contact name.
HTML
<div id="oninitExample">
<div {}="{root}:contact">
Name: <span {}="name;{oninit}:oninit"></span><br />
Address: <span {}="address;"></span><br />
City: <span {}="city;"></span>, State: <span {}="state;"></span> Zipcode: <span {}="zipcode;"></span>
</div>
</div>
Javascript
let oninitModel = {
contact: {
oninit: (ctx, e) => e.textContent = e.textContent + ' (initialized)',
name: 'Jim',
address: '1234 Main',
city: 'New York City',
state: 'NY',
zipcode: '81000'
}
};
_M_.fill(document.getElementById('oninitExample'), oninitModel);
{template}
The {template} directive specifies a document fragment to use for an array element. This example has two templates that can be added by clicking on buttons. One template shows a count and the other shows the time.
HTML
<div id="templateExample">
<template id="templateOne">
<div style="color:red;border:1px solid black;display:inline-block;">
Template One (<span {}="count"></span>)
</div>
</template>
<template id="templateTwo">
<div style="color:blue;border:1px solid blue;display:inline-block;">
Template Two (<span {}="time"></span>)
</div>
</template>
<button {}="onclick:addTemplateOne">Add Template One</button>
<button {}="onclick:addTemplateTwo">Add Template Two</button>
<div>
<div {}="items;{template}:activeTemplate" style="margin-top:10px;">
</div>
</div>
</div>
Javascript
let fragmentOne = document.getElementById('templateOne').content;
let fragmentTwo = document.getElementById('templateTwo').content;
let templateModel = {
templateOneCount: 0,
templateTwoCount: 0,
addTemplateOne: (ctx) => () => {
ctx.root.templateOneCount++;
ctx.root.items.push({
activeTemplate: fragmentOne,
count: ctx.root.templateOneCount
});
},
addTemplateTwo: (ctx) => () => {
ctx.root.templateTwoCount++;
ctx.root.items.push({
activeTemplate: fragmentTwo,
time: (ctx) => {
setInterval(() => { ctx.parent.time = ctx.parent.time; }, 1000); // set up automatic update every second
ctx.parent.time = () => { return (new Date()).toLocaleTimeString(); }; // modify time property to get current time
return ctx.parent.time();
}
});
},
items: []
};
_M_.fill(document.getElementById('templateExample'), templateModel);
{base}
The {base} directive allows access to the original object used to fill elements. This is useful when using arrays or the {root} directive that are filling with a child object.
HTML
<div id="baseExample">
<div {}="{root}:contact">
Name: <span {}="name;:{base}.stylize"></span><br />
Address: <span {}="address;"></span><br />
City: <span {}="city;"></span>, State: <span {}="state;"></span> Zipcode: <span {}="zipcode;"></span>
</div>
</div>
Javascript
let baseModel = {
stylize: (ctx,e) => e.style.fontWeight='bold',
contact: {
name: 'Jim',
address: '1234 Main',
city: 'New York City',
state: 'NY',
zipcode: '81000'
}
};
_M_.fill(document.getElementById('baseExample'), baseModel);