JsRender operates on three core elements: templates, containers, and data. A view represents the defined template, while the context refers to the object applied within that view.
Basic Output Syntax
Two primary syntax forms handle value insertion:
{{: expr}}— outputs raw value.{{> expr}}or{{html: expr}}— outputs HTML-encoded value.{{* snippet}}— executes inline custom code.
Example mapping:
{{: person.fullName }} // plain text value
{{> item.description }} // HTML-escaped output
{{* doCustomLogic() }} // run custom script
Conditional Branching and Iteration
Conditional Blocks
Syntax:
{{if condition}} ... {{else condition}} ... {{else}} ... {{/if}}
Usage example:
<script id="tmplPerson" type="text/template">
<p>Name: {{: userName }}</p>
<p>Status:
{{if profile.age >= 18}}
Adult
{{else}}
Minor
{{/if}}
</p>
</script>
const markup = $( "#tmplPerson" ).render( userInfo );
$( "#container" ).html( markup );
Looping Constructs
Simple loop:
<script id="tmplItems" type="text/template">
{{for}}
<li>ID: {{: uid }} | Title: {{: title }}</li>
{{/for}}
</script>
const dataset = [
{ uid: 101, title: 'Alpha' },
{ uid: 102, title: 'Beta' }
];
const result = $( "#tmplItems" ).render( dataset );
$( "#container" ).html( result );
Nested iteration:
<script id="tmplNested" type="text/template">
{{for}}
<li>User: {{: userName }}
<ul>
{{for interests}}
<li>{{:#getIndex() + 1}} - {{:#data}}</li>
{{/for}}
</ul>
</li>
{{/for}}
</script>
const users = [
{ userName: 'Tom', interests: ['Basketball', 'Football'] },
{ userName: 'Lucy', interests: ['Swimming', 'Badminton'] }
];
$( "#container" ).html( $( "#tmplNested" ).render( users ) );
Delegating loops to external templates improves clarity:
<script id="mainTpl" type="text/template">
{{for}}
<li>User: {{: userName }}
<ul>{{for hobbies tmpl="#hobbyTpl" /}}</ul>
</li>
{{/for}}
</script>
<script id="hobbyTpl" type="text/template">
<li>{{:#getIndex() + 1}}: {{:#data}}</li>
</script>
Accessing outer scope from inner loops via parameters:
<script id="familyTpl" type="text/x-jsrender">
<tr>
<td>{{:#index + 1}}</td>
<td>{{: personName }}</td>
<td>{{: yearsOld }}</td>
<td>
{{for relatives ~idx=#index ~nm=personName ~yr=yearsOld}}
<b>{{:~idx + 1}}.{{:#index + 1}}</b> {{:~nm}}'s {{:#data}} {{:~yr}}
{{/for}}
</td>
</tr>
</script>
const familyData = [
{ personName: 'Zhang San', yearsOld: 3, relatives: ['Dad','Mom','Bro'] },
{ personName: 'Li Si', yearsOld: 4, relatives: ['Grandpa','Grandma','Uncle'] }
];
$( "#tbody" ).append( $( "#familyTpl" ).render( familyData ) );
Advanced Composition and Logic Separation
Template Inclusion
Embed reusable sections using include:
<script id="personBlock" type="text/x-jsrender">
<div>{{: fullName }} resides in {{include tmpl="#locationBlock" /}}</div>
</script>
<script id="locationBlock" type="text/x-jsrender">
<b>{{> cityInfo.name }}</b>
</script>
const people = [
{ fullName: 'Pete', cityInfo: { name: 'Seattle' } },
{ fullName: 'Heidi', cityInfo: { name: 'Sidney' } }
];
$( "#output" ).html( $( "#personBlock" ).render( people ) );
Custom Tags and Helpers
Helpers provide cleaner separation of logic:
Defining a helper:
$.views.helpers({
checkSpecialPrice: function( val ) {
const digits = (val + '').split('').map(Number);
return val === digits.reduce((sum,d) => sum + Math.pow(d,3), 0);
}
});
Using it in a template:
<script id="priceTpl" type="text/x-jsrender">
<tr>
<td>{{: itemName }}</td>
<td>
{{if ~checkSpecialPrice(unitPrice)}}
{{: unitPrice }}
{{else}}
--
{{/if}}
</td>
</tr>
</script>
Value Cnoverters
Converters transform displayed values:
Registering a convertre:
$.views.converters({
upperCase: function( str ) {
return str ? str.toUpperCase() : '';
}
});
Applying in template:
<script id="convTpl" type="text/template">
{{for}}
<li>Uppercase Name: {{upperCase:#parent.data.userName}}</li>
{{/for}}
</script>