A simple, lightweight, efficient and non-invasive pure-JavaScript templating engine
Embed references to an object's property and function member values, optionally drilling through the object hierarchy with an intuitive pathing scheme.
Employ familiar "if-elseif-else" conditional logic to easily craft templates that adapt to any situation.
Target collections including both arrays and object members for looping, indexing and positional item template expansion.
Use the Model-Template-View (MTV) design pattern, synthesizing dynamic view objects by embedding view-specific code directly into template definitions.
Kruntch.js is a simple, pure-JavaScript templating engine that allows you to efficiently generate text-based content from your JavaScript object model using a convenient and familiar template methodology.

Typically, Kruntch.js templates are used to generate HTML content thereby helping to separate presentation elements and user-interface logic from a JavaScript object model, but Kruntch.js is not limited to generating just HTML... Kruntch.js can generate any textual content, allowing for interesting data-transformation uses as well.

As a strictly complementary and non-invasive library, Kruntch.js can be used with virtually any client-side presentation framerowk without fear of incurring unwanted DOM manipulation or other overhead.

Kruntch.js can even be used on the server-side as a Node.js Module allowing for server generated presentations as well as numerous data transformation possibilities.

Put simply, Kruntch.js primarily consists of a single Apply() method that takes as input parameters a template definition and a JavaScript object instance and returns a string of text ( ... typically HTML), what you do with the text from that point on is up to you!

Getting Started
Installing Kruntch.js for client-side use is as simple as downloading the Kruntch.js JavaScript and CSS files, adding them to your project and referencing them in your HTML page.

The following is a minimal HTML page with Kruntch.js "installed" and a simple call to Apply() an empty template definitiion:
<html>
<head>
<link type="text/css" href="style/kruntch.css" rel="stylesheet" />
<script type="text/javascript" src="js/kruntch.min.js" />
<script type="text/javascript">

// Handle the document ready ( ... example using jQuery)
$(document).ready(function () {

// Apply the template
Kruntch.Apply(
'YourTemplateID',
{ YOUR OBJECT DEFINITION },
function(html) {

// Do something with the resultant HTML

}
);

}

</script>
</head>
<body>

YOUR PAGE HTML

<!-- Kruntch.js Template Definitions (hidden textarea with template content) -->
<textarea data-templateid="YourTemplateID" class="template">
YOUR TEMLATE DEFINITON
</textarea>
</body>
</html>
Installing Kruntch.js for server-side use is as simple as downloading the Kruntch.js Node.js module, adding it to your Node.js project (or other standard Node.js module location) and referencing it in your node script.

The following is a minimal node script with Kruntch.js "installed" and a simple call to Apply() an empty template definitiion:
// Require the Kruntch.js template engine
var Kruntch = require('./kruntch.node.js');

// The Kruntch.js template definition
var template = "YOUR TEMPLATE DEFINITON";

// The JavaScript object
var object = { YOUR OBJECT DEFINITION }

// Apply the template
Kruntch.Apply(
template,
object,
function(text) {

// Do something with the resultant text

}
);

Template Basics
Templates for client-side presentations are generally defined in your HTML page as hidden textareas and are identified to Kruntch.js through the use of the data-templateid HTML attribute as follows:
<textarea data-templateid="YourTemplateID" class="template">
YOUR TEMLATE DEFINITON
</textarea>
Alternatively, you can source your template definition within a <script> tag as follows:
<script data-templateid="YourTemplateID" type="text/x-kruntch-template">
YOUR TEMLATE DEFINITON
</script>
Or... you can even use the new HTML5 <template> tag as follows:
<template data-templateid="YourTemplateID">
YOUR TEMLATE DEFINITON
</template>
In the simplest sense, Kruntch.js templates contain both textual markup ( ... HTML markup for a presentation template) and references to a JavaScript object's members.

Object references can be simple scalar property references used to access values to be embedded into the resulatnt text or can form more advanced instructions for generating text based on the object's state.

A baisc JavaScript object and HTML-based Kruntch.js template with simple property references might look as follow:
// Sample JavaScript object
var obj = {
Name: 'PugLover1980',
CreatedOn: '01/01/2004',
EMail: 'puglover1980@puglover.com',
Gender: 'M',
DateOfBirth: '01/01/1980',
}

<!-- Sample Kruntch.js template -- >
<textarea data-templateid="contact" class="template">
<div class="contact">
<div class="name">[Name]</div>
<div class="email">[Email]</div>
<div class="gender">[Gender]</div>
</div>
</textarea>
More advanced object references include the <if> statement used to conditionally expand template content based on a typical boolean logic expression and the <for> loop used to interate over a collection and perform a template expansion for each collection item.

Further, both <if> statements and <for> loops can be nested allowing for the creation of very rich templates that adapt to objects with more complex state.

Applying the Kruntch.js template to a particular JavaScript object is done in JavaScript using the Kruntch.Apply() method as follows:
var text = Kruntch.Apply("YourTemplateID", YourObject);

// Now do something with the resultant text
Alternatively, you can simply pass in the content of your template to the Kruntch.Apply method as follows:
var template = "<template>YOUR TEMLATE DEFINITON</template>";
var text = Kruntch.Apply(template, YourObject);

// Now do something with the resultant text
Note that determining when to apply your Kruntch.js templates is up to you and your application's particular needs.

Kruntch.js does NO behind the scenes maipulation, so it's up to you to make one or more calls to Kruntch.Apply() in order to generate the resultant text and then use it as you see fit.

Now, with the basics out of the way, let's take a look at some example HTML templates in order to see how Kruntch.js really works.

Examples
The following examples will take you through the entire process of defining and using HTML-based Kruntch.js templates ranging from the simplest property expansion to looping, filtering, indexing, targeting and dynamic Model-Template-View (MTV) view objects.

First, let's consider the following JavaScript object instance defining the data related to a typical blog:
var blog = {
Author: {
Name: 'PugLover1980',
CreatedOn: '01/01/2004',
EMail: 'puglover1980@puglover.com',
Gender: 'M',
DateOfBirth: '01/01/1980',
ProfileImage: 'images/puglover_profile.png',
Age: function () {
var today = new Date();
var birthDate = new Date(this.DateOfBirth);
var age = today.getFullYear() - birthDate.getFullYear();
var mdelta = today.getMonth() - birthDate.getMonth();
return (mdelta < 0 || (mdelta === 0 && today.getDate() < birthDate.getDate())) ? --age : age;
}
},
Title: 'A Pug's Life',
SubTitle: 'The un-edited ramblings of a random pug lover.',
Posts: [
{
Title: 'Pugs are freaky looking little loafers!',
PublishedOn: '03/01/2013',
Image: 'images/pug1.jpg',
Content: 'Lorem ipsum dolor sit amet, consectetur adipisicing elit, sed do eiusmod
tempor incididunt ut labore et dolore magna aliqua. Ut enim ad minim veniam, quis
nostrud exercitation ullamco laboris nisi ut aliquip ex ea commodo consequat.
Duis aute irure dolor in reprehenderit in voluptate velit esse cillum dolore eu
nulla pariatur. Excepteur sint occaecat cupidatat non proident, sunt in culpa qui
officia deserunt mollit anim id est laborum.',
Labels: ['Pug', 'Freaky', 'Dog', 'Snout'],
Comments: [
]
},
{
Title: 'Pugs... the New White Meat!',
PublishedOn: '02/25/2013',
Image: 'images/pug2.jpg',
Content: 'Lorem ipsum dolor sit amet, consectetur adipisicing elit, sed do eiusmod
tempor incididunt ut labore et dolore magna aliqua. Ut enim ad minim veniam, quis
nostrud exercitation ullamco laboris nisi ut aliquip ex ea commodo consequat.
Duis aute irure dolor in reprehenderit in voluptate velit esse cillum dolore eu
nulla pariatur. Excepteur sint occaecat cupidatat non proident, sunt in culpa qui
officia deserunt mollit anim id est laborum.',
Labels: ['Pug', 'Silly', 'Dog', 'Rodent', 'Alien'],
Comments: [
]
},
{
Title: 'Teach Your Pug to Check Your Voicemail.',
PublishedOn: '02/22/2013',
Image: 'images/pug3.jpg',
Content: 'Lorem ipsum dolor sit amet, consectetur adipisicing elit, sed do eiusmod
tempor incididunt ut labore et dolore magna aliqua. Ut enim ad minim veniam, quis
nostrud exercitation ullamco laboris nisi ut aliquip ex ea commodo consequat.
Duis aute irure dolor in reprehenderit in voluptate velit esse cillum dolore eu
nulla pariatur. Excepteur sint occaecat cupidatat non proident, sunt in culpa qui
officia deserunt mollit anim id est laborum.',
Labels: ['Pug', 'Voicemail', 'Dog', 'Smooshed Face'],
Comments: [
]
}
]
};

Properties
Kruntch.js allows you to embed references to an object's property and function member values, optionally pathing into and through sub-objects with an intuitive pathing scheme as follows:
    [ScalarPropertyName]
    Replace this reference with the value of the scalar property identified within the square brackets.
    [SubObjectPropertyName.ScalarPropertyName]
    Path into the specified sub-object property member, replacing this reference with the value of the scalar property identified within the square brackets.
    [FunctionName]
    Replace this reference with the result of calling the function identified within the square brackts. The function call is made with no parameters and with the sub-object instance established as the value of "this" wihing the function scope. The result is converted to a string using the JavaScript "toString()" method.
    [SubObjectPropertyName.FunctionName]
    Path into the specified sub-object property, replacing this reference with the result of calling the function identified within the square brackets.
    [SubObjectPropertyName.FunctionName.ScalarPropertyName]
    Path into the specified sub-object property, calling a specified function member that returns another object instance and then replacing this reference with the value of the scalar property identified within the square brackets.
It's important to note that this pathing scheme is NOT limited to the cases outlined above, they are simply there as examples to help you understand the extent to which you can path through an object's sub-objects, properties and functions.

The key is, all sub-objects, whether they are direct members or are dynamiclaly returned as the result of a function call, can be pathed through but ultimately all references must end in a scalar value even if that value is the result of a parameter-less function call.

Now, let's use property expansion to develop a template that generates a typical blogger profile panel given the blog object above as follows:
<textarea data-templateid="profile" class="template">
<div class="profile">
<div class="imagecell">
<img src="[Author.ProfileImage]" class="image" />
</div>
<div class="detailscell">
<div class="name">[Author.Name]</div>
<div class="personal">[Author.Age] year old - [Author.Gender.toUpperCase]</div>
<div class="saying">"[Author.FavoriteSaying]"</div>
<div class="since">Since: [Author.CreatedOn]</div>
<div class="contact"><a href="mailto:[Author.EMail]">Contact Me</a></div>
</div>
</div>
</textarea>

Which results in:
Notice that in the above example, Author identifies the author sub-object of the blog object defined above and that while most property values embedded in the template are references to simple scalar properties (i.e. [Author.Name], [Author.FavoriteSaying], etc.), [Author.Age] actually referes to a member function that calculates the blog author's age based on their DateOfBirth.

Also, note that for the detail line that includes the author's Gender, the value reference [Author.Gender.toUpperCase] is formatting the gender value to upper-case using the built-in JavaScript toUpperCase() string member function.

Conditionals
Kruntch.js allows you to easily leverage the conditional if-elseif-else statement in order to create conditional logic that can help your template to adapt many different situations.

The basic if-elseif-else conditional form looks as follows:
<textarea data-templateid="YourTemplateID" class="template">
<if condition="this.Something == somevalue">
... apply this sub-template ...
<elseif condition="this.Something == someOtherValue">
... apply this sub-template ...
</elseif>
<else>
... apply this sub-template ...
</else>
</if>
</textarea>
Now, let's use some basic conditional logic to develop a simple blog header as follows:
<textarea data-templateid="header" class="template">
<div class="blog">
<div class="header">
<div class="title">[Title]</div>
<if condition="((this.SubTitle != undefined) && (this.SubTitle != ''))">
<div class="subtitle">[SubTitle]</div>
</if>
</div>
</div>
</textarea>

Which results in:
Note, that since the content within each conditional element (if, elseif, else) is treated as a template itself (... a sub-template), conditionals can be nested and, in fact, any Kruntch.js template construct can be included within this sub-template.

Looping & Indexing
Looping and indexing allows you to apply Kruntch.js templates to collection items either by iterating over every collection item or by targeting exact collection items.

The basic looping form looks as follows:
<textarea data-templateid="YourTemplateID" class="template">
<for each="Collection">
... apply this sub-template ...
</for>
</textarea>
The basic indexing form looks as follows:
<textarea data-templateid="YourTemplateID" class="template">
<with in="Collection">
<nth at="0">... apply this sub-template ...</nth>
<nth at="1">... apply this sub-template ...</nth>
<nth at="2">... apply this sub-template ...</nth>
</with>
</textarea>
Again, as in the case of the if-elseif-else conditional, the content of the <for> and <with> elements are, in fact, sub-templates so for-loops and with-indexes can be nested and all other Kruntch.js constructs can be utilized as well.

Note that the each attribute identifying the collection to be iterated over works the same as the property reference in that it can be used to path through the hierarchy of an object and it's sub-objects (or property and function members) to access a collection at any level.

Also, a targeted collection can either be a JavaScript array or a JavaScript object.

When a JavaScript object is used as a collection, its members will be iterated over and can be explicitly targeted via their member names as we will see below.

But first, let's use some simple looping to generate the blog post entries:
<textarea data-templateid="post" class="template">
<div class="blog">
<for each="Posts">
<div class="post">
<div class="imagecell">
<img src="[Image]" class="image" />
</div>
<div class="title">[Title]</div><br />
<br />
<div class="byline">
<br />by: <a href="#">[Parent.Author.Name]</a> on [PublishedOn]
</div>
<div class="content">
[Content]
</div>
<div class="labels">
<span class="italic">Labels:</span>
<for each="Labels">
<span class="label">
<a href="#">[$]</a>, 
</span>
<last>
<span class="label">
<a href="#">[$]</a>
</span>
</last>
</for>
</div>
</div>
</for>
</div>
</textarea>
Which results in:
Notice that in the above template there are two loops, one iterating over the Posts collection and the other iterating over the Labels collection of each Post object.

This again demonstrates the nested nature of Kruncth.js templates where the application of a loop simply results in the loop's content being considered a sub-template to be applied to each collection item.

Further, as the item sub-template is being applied, collections within the item are subject to the application of additional sub-templates as in the case of the post Labels collection.

Thus, you can consider the above template as a hierarchal group of templates, one for generating the content of the top-level Blog, a sub-template for generating each Post content and finally another sub-template for generating the Label content.

Looking a little closer at the Labels sub-template two additional features, loop literals and item targeting, can be seen:
<div class="labels">
<span class="italic">Labels:</span>
<for each="Labels">
<span class="label">
<a href="#">[$]</a>, 
</span>
<last>
<span class="label">
<a href="#">[$]</a>
</span>
</last>
</for>
</div>
Loop Literals
The property reference [$] represents the current literal value of a collection item in the event that the item is a scalar value.

For example, in the case of the Labels collection, each item is simply the label string so the [$] will be replaced with the value for each label.

The following outlines the purpose and use of each of the loop literal references:
    [$]
    Replace this reference with the value of the current collection item. Collection items are converted to a literal string value using the JavaScript toString() method of the value.
    [#]
    Replace this reference with the current literal index value of the current collection item.
    [##]
    Replace this reference with the current literal collection count of items.
Item Targeting
The collection item targeting construct <last> is used to designate a sub-template to be applied against just the last item of a given collection.

For example, in the template above, <last> was used to prevent a comma from following the last Label item.

Note that the sub-template used for all the other items other than the last in the above example was defined by the content of the for loop excluding the <last> element.

In a sense, all the item tagets are removed from the <for> sub-template content and what content remains represents the template that is applied to all items that don't match a specific item target reference.

The following outlines the purpose and use of each of item targets:
    <first>
    Targets the first item of the collection for the application of a specific sub-template.
    <last>
    Targets the last item of the collection for the application of a specific sub-template.
    <empty>
    Targets the collection owner for the application of a specific sub-template in the event that the specified collection is empty.
    <nth>
    Targets a collection item, as specified by the following properties, for the application of a specific sub-template:
    at - Specifies the exact collection index of the item to target. Alternatively at can specify multiple indices separated by commas such as "1,3,9".

    every - Specifies a value for a modulo operation on the items index allowing you to target every 2nd item or 3rd item etc. The sub-template will be used for the item if the ((item's index MOD "every" value) == 0).

    where - Specifies a specific condition test to perform on the item in order to determine if the sub-template will be used. For example, "this.Size == 'Large'" would return true if items Size property value was "Large" and thus this sub-template would be used for "Large" items.
Now, let's use some simple indexing to generate a panel displaying the last three posts:
<textarea data-templateid="post" class="template">
<div class="blog">
<div class="latest">
<div class="title">Latest Posts</div>
<with in="Posts">
<nth at="0,1,2">
<div class="item"><a href="#">[Title]</a></div>
</nth>
</with>
</div>
</div>
</textarea>
Which results in:
Item Filtering
Both the <for> and <with> constructs can specify a filter criteria that will filter the collection prior to enumeration through the use of the where attribute which specifies a criteria to test on each item.

For example, the following template generates a search panel that can be used to filter blog posts by Title:
<textarea data-templateid="search" class="template">
<div class="blog">
<div class="searchpanel">
<div class="search">
<input id="txtTerm" type="text" placeholder="Search Term" value="[Criteria]" class="terms" /> 
<input id="cmdGO" type="button" value="Search" class="go" />
</div>
<div class="results">
<for each="Posts" where="this.Title.indexOf(this.Parent.Criteria) > -1">
<a href="#"><div class="result">[#]. [Title]</div></a>
<empty>
<div class="result">No results were found.</div>
</empty>
</for>
</div>
</div>
</div>
{{
Ready: function() {

// Establish a "me" reference
var me = this;

// Use jQuery to handle the "search" click event
$('#cmdGO').on('click', function() {

// Set the "criteria" value
me.Criteria = $('#txtTerm').val();

// Re-Render the "search" template
Kruntch.Apply('search', me, $('#search')[0], true);

// Return
return;

});

// Return
return;

}
}}
</div>
</textarea>
Which results in:
Notice that in the above example, the Posts collection is filtered by post titles that contiain the value Parent.Criteria.

Parent is property member that is automatically generated by Kruntch.js on each item view object processed during loop and index operations.

Notice also that jQuery is being used to handle the search button's click event as well as other aspects of the implementation.

Finally, notice that there is a function defined in the root of the template named Ready which is optional and if present, will be called by Kruntch.js just prior to returning the generated result text to the caller.

MTV View Objects
Model-Template-View view objects help you to separate your view-specific code from your object/data-model code by allowing you to associate view-spcific code directly to your template definitions.

When your template is applied, an MTV view object is synthesized as the union of all the data/functionality of the supplied object/data-model AND all the code segments embedded in your template definition.

This way, your object/data-model functionality resides with your object definition while the view-related functionality resides with your template definition.

The following template demonstrates some simple uses of MTV view object functionality:
<textarea data-templateid="profile" class="template">
<div class="blog">
<div class="profile">
<div class="imagecell">
<img src="[Author.ProfileImage]" class="image" />
</div>
<div class="detailscell">
<div class="name">[Author.Name]</div>
<div class="personal">[Author.Age] year old - [GenderText]</div>
<div class="saying">"[Author.FavoriteSaying]"</div>
<div class="since">Since: [Author.CreatedOn] - ([DaysBlogging] days)</div>
<div class="contact"><a href="mailto:[Author.EMail]">Contact Me</a></div>
</div>
</div>
</div>
{{
GenderText: function() {
if (this.Author.Gender == 'M')
return 'Male';
else if (this.Author.Gender == 'F')
return 'Female';
return 'Unknown';
},
DaysBlogging: function() {
return Math.floor((((new Date()) - (new Date(this.Author.CreatedOn))) / (1000 * 60 * 60 * 24)));
}
}}
</textarea>
Which results in:
The functions GenderText and DaysBlogging are extracted from the template definition and aggregated into a view object that also includes all the members of the object/data-model, which, in this case, is the blog object.

Notice that the template can then access these functions in just like any of the other native members of the object/data-model instance.

Also note that these view functions can also be defined within any sub-template including if, for and with sub-templates.

In the case of for and with elements, an MTV view object is created for each collection item processed.

The following template demonstrates using collection item MTV view objects:
<textarea data-templateid="profile" class="template">
<div class="blog">
<div class="latest">
<div class="title">Latest Posts</div>
<with in="Posts">
<nth at="0,1,2">
<div class="item"><a href="#">[TitleText]</a></div>
{{
TitleText: function() {
if (this.Title.length > 20)
return this.Title.substr(0, this.Title.indexOf(' ', 20)) + ' ...';
return this.Title;
}
}}
</nth>
</with>
</div>
</div>
</textarea>
Which results in:
Binding
In order to access a given MTV view object outside of a template expansion operation, you can call Kruntch.Bind() which takes the same parameters as Kruntch.Apply() but returns the MTV view object instead of the generated text.

Once bound, you can then access all the MTV view function defined within your template definition right from the bound object itself.

Try it out!
Fork a sample @


OR

Use the editor below to give Kruntch.js a try right now!
 
Template
Object
Output