Search code examples
jqueryhtmltemplatesunderscore.js-templatinghtml5-template

jquery and HTML5's template tag


I want to use underscorejs' templating function. It seems like HTML5's <template> tag would be an AMAZING fit for this, but there's a snag... The underscorejs interpolation tags (<% and %> get html-escaped, so HTML inside a template tag looks like so:

$('template.new-email').html()

=>

"
  <div class="email">
    <div class="timestamp">
      &lt;%= received %&gt;
    </div>
    <div class="from">
      &lt;%= from %&gt;
    </div>
    <div class="title">
      &lt;%= title %&gt;
    </div>
    <div class="message">
      &lt;%= message %&gt;
    </div>
  </div>
"

Well, that sucks.

Now, as it turns out, if I use a script tag with a fictitious type, like "x-underscore-templates", then it looks hunky-dory:

$('.new-email').html()

=>

"
  <div class="email">
    <div class="timestamp">
      <%= received %>
    </div>
    <div class="from">
      <%= from %>
    </div>
    <div class="title">
      <%= title %>
    </div>
    <div class="message">
      <%= message %>
    </div>
  </div>
"

So my question is -- can I use the template tag? How do I get just the characters I need, in a string, so I can pass them to underscore's templating system?

Note - since the server I'm using right now is a hapijs / node server that uses handlebars as a server-side templating system, I can't just use {{ and }}.


Solution

  • I also like the idea of using a template tag and I have tried to make underscore templates work in the html5 template element in various ways. Unfortunately, the template element specifically means a html template and the content will be transformed into a document fragment which is not appropriate for many valid underscore templates even if they will later render to valid html.

    Consequently, the only usage I can suggest is that you could keep your script elements organized within a template element like so:

    <template class="underscore-templates">
     <script id="new-email">
       <div class="email">
         <div class="timestamp">
           <%= received %>
         </div>
         <div class="from">
           <%= from %>
         </div>
         <div class="title">
           <%= title %>
         </div>
         <div class="message">
            <%= message %>
         </div>
       </div>
     </script>
     <script id="other">
     </script>
    </template>
    

    And then they are segregated to safely do things like:

    var templates = $('.underscore-templates').prop('content');
    _.template($(templates).children('#new-email').html(), {...});
    

    with the template element serving as a scope to prevent the normal issues of id collision and executing these templates as scripts.

    (Still, this would be limited to modern browsers without a pretty in depth investigation of how (or maybe if) you can retrieve the template elements content in older browsers and render it into a searchable fragment.)