I wanted to figure out how I could turn the following object:
var Q = {'questions': [
{
'id': "Q1",
'text': "Is this is a question?",
'answers': [
{ 'id': "Q1A", 'text': "An answer" },
{ 'id': "Q1B", 'text': "Another answer" },
{ 'id': "Q1C", 'text': "One more answer" },
{ 'id': "Q1D", 'text': "Can't have fewer than for answers!" },
],
},
{
'id': "Q2",
'text': "Is this another question?",
'answers': [
{ 'id': 'Q2A', 'text': "Unimaginative answer" },
{ 'id': 'Q2B', 'text': "Dull answer" },
{ 'id': 'Q2C', 'text': "Boring is a town in Oregon" },
{ 'id': 'Q2D', 'text': "Can't handle any more answers" },
],
},
]};
into the following HTML in the browser:
<section class="slide question">
<h2>Is this is a question?</h2>
<ol>
<li>An answer</li>
<li>…</li>
<li>…</li>
<li>…</li>
</ol>
</section>
etc … etc
Up to this point, I had been content with generating whole HTML documents using either HTML::Template or Template-Toolkit, but, in this case, I wanted my application to serve a shell document which would then be populated using a JSON document to be retrieved a little later.
I looked at a number of JavaScript templating solutions such as _.template, mustache, pure and a few others I do not remember. String concatenation hell immediately pushed me away from _.template
. With pure.js
, I wasn’t able to understand the documentation enough to do anything other than the provided canned examples. And, I still don’t understand how to deal with nested data structures using mustache.js
. All of my difficulties are no doubt due to my shortcomings, but that does not matter any more.
I was immediately able to understand how to solve my problem using Handlebars.js. Too bad that was the last one I tried.
First, I defined the template:
<script id="question-template" type="text/x-handlebars-template">
{{#each questions}}
<section class="slide question">
<h2>{{text}}</h2>
<ol>
{{#each answers}}
<li>{{text}}</li>
{{/each}}
</section>
{{/each}}
</script>
I don’t know about you, but, in my mind, this felt very similar to what I would have written with HTML::Template
and I found that comforting.
Then, assuming Q holds the object mentioned above, it was a simple matter of getting the source of the template from the DOM, compiling it, rendering it with the appropriate context, and inserting it into the right place using JQuery:
var source = $("#question-template").html();
var template = Handlebars.compile(source);
var html = template(Q);
$('.deck-container').prepend(html);