About fifteen years ago at a startup, I built a very data-heavy single page app for biologists to manage a map/reduce version of a gene sequencing engine, and because it was data heavy, it made use of templates to render much of the HTML. If you've ever been in this situation, you reach for a library.
With HTML Templates, you might not need a library. But I suspect you're going to want one.
There were a few templating libraries available back then, such as Mustache and Handlebars, but we were already using lodash, and Lodash has an embedded templating library already. So our code was filled with text like this:
<script id="pipeline-job-minibar-template" type="text/x-underscore-tmpl">
<tr data-cid="<%= cid %>">
<td><%= url.split('/').pop().split(':').pop() %></td>
<td><%= state[0].toLocaleUpperCase() + state.slice(1, state.length) %></td>
<td>
<% if (state === 'running') { %><%= Math.floor(total_progress * 100) %><% } else { %><%= fcompleted %><% } %>
</td>
</tr>
</script>
The type="text/x-underscore-tmpl"
attribute prevented browsers from
trying to compile or run the template as code, and the id
allowed us
to find the code, import it as text, compile it with lodash, and run it
in the browser environment. By using some clever context management to
sneak variables like url
and state
into the lexical scope of the
template compiler, we got a lot of mileage out of those templates.
I was intrigued to see that both HTML and Javascript now have their own "templating" features. In Javascript, anything written with backticks and including a special variable access syntax will instead replace that that syntax with the contents of any lexically available variable:
const name = "Elf";
const greeting = `Hello, ${name}!`;
console.log(greeting); // -> "Hello, Elf!"
This is available in the 2016 version of Javascript and supported by all major browsers except, of course, Internet Explorer.
HTML Templates are a little different. They're just a tag,
\<template\>
, which basically tells HTML to not render the contents.
It's invisible to the browser. A template might look like this:
<template id="entry-template">
<li class="entry">
<a>
<span class="pubdate"></span>
<span class="storytitle"></span>
</a>
</li>
</template>
<ul id="stories"></ul>
And given a list of stories, you might render them this way (this is, in fact, the way they're rendered in the story rendering engine I use on my writing site:)
const storylist = document.getElementById('stories');
const storytemplate = document.getElementById('entry-template');
stories.forEach((story) => {
const template = document.importNode(storytemplate.content, true);
template.querySelector('a').setAttribute('href', story.url);
template.querySelector('.pubdate').appendChild(document.createTextNode(story.pub_date));
template.querySelector('.storytitle').appendChild(document.createTextNode(story.title));
storylist.appendChild(template);
});
The only thing to note here, aside from the usual low-level DOM
manipulation, is presence of the
document.importNode(template.content,true)
command. This command makes
a copy of the original template, and the true
says to include
all the child objects in the template.
And that's pretty much all templates are. They're just chunks of HTML
that you can use as DOM objects, cloning them and modifying them at
will, in order to support outputting heavy collections of data. There's
not a lot of magic here, and it would definitely get old fast writing
all those querySelector
commands, so some sort of library would be
nice on top of this. I haven't delved deep into who's doing this, but
both Polymer and
Lightning
use native templates rather than rolling their own.
The thing is, compared to "rolling your own" in Javascript, this stuff is fast. The browsers are optimized for it. Every layer of abstraction gets you further away that speed, and speed is everything in this business. So learn it, because while it may not be the future, it's a future you should be aware of whenever you need that last hundred milliseconds of responsiveness.