​Today, I was working on a code base for a time sheeting system. It does a lot of rendering on client side like retrieving appointments and source code comments from third party system and then renders it onto the page.

​Unfortunately, the javascript that did the rendering post ajax call was something like this:

for (var i = 0; i < wi.CheckinHistory.length; i++) {
history += "<li><i class=\"add-note\" title=\"Add this checkin comment to the Notes field\">" + wi.CheckinHistory[i] + "</i></li>";
}
var item = "<span class=\"wi-link\"><a href=\"" + wi.Url + "\" target=\"_blank\">[" + wi.Id + "]</a></span>" +
"<span class=\"wi-title\">" + wi.Title + "</span>" +
"<span class=\"wi-state\">" + wi.State + "</span>" +
"<span class=\"wi-project\">" + wi.ProjectName + "</span>" +
"<span class=\"wi-checkins\"><ul>" + history + "</ul></span>" +
"<span class=\"wi-modified\">" + "(Last Modified " + modDate + " by " + wi.ChangedBy + ")</span>";
return item;

​This is obviously not maintainable as it's not really readable and prone to error. 

I refactored this code and re-implemented it using a javascript templating engine. There are several around and LinkedIn has a good smackdown of several options

I chose to use Handlebars​ because of the easy to read syntax and extensible (but mainly because it has an awesome logo).

Installing and using Handlebars

Grab it from NuGet using :

Install-Package Handlebars.js

​Reference the handlebars.min.js in your layout/master page.

Create your template, the javascript that builds html above will become nice and readable:​

    <script id="tfsChangeSetTemplate" type="text/x-handlebars-template">
<h3>Changesets ({{count result}})</h3>
{{#each result}}
<div class="wi-item">
<span class="wi-link"><a href="{{Url}}" target="_blank">[Changeset {{Id}}]</a></span>
<span class="wi-title">Checked In {{CommitDateFormatted}} by {{CommittedBy}} </span>
<span class="wi-state">{{Changes}} file(s) changed</span>
<span class="wi-checkins">
<ul>
<li>{{#if Comment}}
<i class="add-note" title="Add this checkin comment to the Notes field">{{html Comment}}
</i>
{{else}}
<i>No comment was entered
</i>
{{/if}}
</li>
</ul>
</span>
{{#if WorkItems}}
<span class="wi-workitems">
<ul style="list-style: none; margin-left: 20px;">
{{#each WorkItems}}
<li>
<span class="wi-link"><a href="{{Url}}" target="_blank">[WI {{this.Id}}]</a></span>
<span class="wi-title">{{Title}}</span>
<span class="wi-state">{{State}}</span>
<span class="wi-project">{{ProjectName}}</span>
</li>
{{/each}}
</ul>
</span>
{{/if}}
</div>
{{/each}}


</script>

You'll notice I put in some conditional logic using the IF block and made extensive use of the EACH block to loop through the JSON data.​

The javascript to get and render the template is:​

if (data.length > 0) {
var tfsWorkItemTemplate = Handlebars.compile($("#tfsChangeSetTemplate").html());
var html = tfsWorkItemTemplate({ result: data });
$tasks.append(html);
}

Nice and simple!​

Comment