0

Based on Nicholas Zaka's book 'Maintainable JavaScript', I understand that the best way to put a small HTML template in my page is to add something like:

    <script type="text/x-templates" class="templates">
            <div class="template1"> ... </div>
            <div class="template2"> ... </div>
            ...
    </script>

I like this approach better than placing my templates in the <body> and hide them using css because these would still be displayed in browsers like dillo.

The way I'm currently grabbing them with jQuery is this:

    var $templates = $('<div/>').append($('.templates').text()).children();

Things that I tried that didn't work are:

    var $templates = $('.templates');
    var $templates = $($('.templates').text());
    var $templates = $($('.templates').html());

The solution I have now works but it doesn't seem to me very elegant. What would be the best way to do this?

Oscar
  • 915
  • 10
  • 15
  • You should have tried these 3 keywords in Google **jquery html templating** ---> http://stephenwalther.com/archive/2010/11/30/an-introduction-to-jquery-templates.aspx – kidwon Apr 03 '13 at 23:24
  • He may be preferring to role his own. – jmar777 Apr 03 '13 at 23:27
  • yes, i would like to avoid using an additional dependency as much as possible but thanks for the link. – Oscar Apr 03 '13 at 23:35
  • use `html()` not `text()` . If you have more than one, `$('.templates').html()` will only return html from first of that class – charlietfl Apr 03 '13 at 23:36

3 Answers3

0

Edit: I think I initially misunderstood your question - I didn't realize you had multiple templates within the same script tag. I would suggest breaking each template into it's own tag, as that may be easier to manage (and then you don't have extra parsing and div tags just to keep them separate). For example, consider this for your template markup:

<script type="text/x-templates" class="template" id="template1">
    [template 1]
</script>

<script type="text/x-templates" class="template" id="template2">
    [template 2]
</script>

And something like this in your JavaScript:

// create a map of templates (keyed by the template's id)
var templates = {};
$('.template').each(function() {
    var $template = $(this);
    templates[$template.attr('id')] = $(this).html();
});

//usage
$('body').append(templates.template1);
$('body').append(templates.template2);

Here's a demo of it in action: http://jsfiddle.net/KyWj6/

jmar777
  • 38,796
  • 11
  • 66
  • 64
  • Thanks jmar777, I like the idea of wrapping all templates as a single object. To follow Snixtor's suggestion I'd change the line `templates[$template.attr('id')] = $(this).html();` for `templates[$template.attr('id')] = $($(this).html().trim());` – Oscar Apr 04 '13 at 00:44
  • The `trim()` is a good idea. Are you sure you want the template map to be to jQuery objects rather than strings though? I ask because then you're dealing with DOM fragments that will be stateful and perhaps have unintended consequences. The strings won't ever have those kinds of "gotchas". – jmar777 Apr 04 '13 at 01:00
  • Hm that's a good point but I guess that poses a different question – Oscar Apr 04 '13 at 01:27
0

Try this:

var $templateHtml = $('.templates').html();
var $templates    = $('<div/>').html(templateHtml);

or alternatively, make it one line:

var $templates    = $('<div/>').html($('.templates').html());
Devin Burke
  • 13,642
  • 12
  • 55
  • 82
0

$($('.templates').html()) will struggle if the inner HTML of the "templates" class starts with a space, so you'd need $($('.templates').html().trim()) instead. You'll end up in further trouble though because the inner HTML of your script tag doesn't have a root node, so you'd instead need something like:

<script type="text/x-templates" class="templates">
    <div>
        <div class="template1">temp1</div>
        <div class="template2">temp2</div>
        ...
    </div>
</script>

You could then get the HTML of template1 with something like:

var templatesCollection = $($(".templates").html().trim());
alert(templatesCollection.children(".template1").html());

But, all this said, why not put each template in its own script tag with an ID? (Class doesn't make much sense unless you're planning on having more than one instance, and in a templating scenario I would assume that's not what you want.)

So something more like:

<script type="text/html" id="template1">
   <div>temp1</div>
</script>

And then a very simple selector: $("#template1").html()

Snixtor
  • 4,239
  • 2
  • 31
  • 54
  • Hi Snixtor, thanks for your reply. You are right I should be using id's for this purpose. I've been trying your approach of using separate script tags but I end up running into the same problem. If I use the .html() I don't end up with a jQuery object. I've also tried $("#template1").children() but since it's considering the content as text it doesn't find any. – Oscar Apr 04 '13 at 00:24
  • You can wrap a html string in `$('html_text_here')`, but there are limitations. As I mentioned above, it can't start with whitespace, so you'll need to trim it, it also needs a root node. - When I say root node, I mean the jQuery object needs to represent a single element (though that element may have children). – Snixtor Apr 04 '13 at 00:31
  • Oups I was forgetting the `trim()`. Ok yes this seems like this is the best approach. So if I'm understanding it correctly as far as I have each template on a separate ` – Oscar Apr 04 '13 at 00:41
  • Provided the inner HTML of the `idofthetemplate` element has a *root* element, yes. Otherwise you won't get a meaningful jQuery object. You'll get one, but it's content probably won't be what you expect. – Snixtor Apr 04 '13 at 00:45