Best practice for storing HTML templates on a page?
Asked Answered
Q

6

23

I'm developing a rather heavy JavaScript interface to a site I'm building, and I've decided to use the (recently made official) jQuery templates plugin to generate my elements from my queries to a JSON API. Now, the problem I'm currently having is:

I'm prone to have a bunch of these templates around. One for each kind of object, some for lists, some for sections of the page, etc. Is there any preferred way of storing these templates? I've read about defining a <script> tag with an id using the template name, and then retrieving the text from there (as John Resig describes in "JavaScript Micro-Templating"), but having a bunch of those <script> tags in every single page looks a bit hackish.

So, the question is: is there any 'best practice' for this kind of scenario?

Quarterly answered 18/11, 2010 at 20:27 Comment(2)
Is the method of that <script> to prevent the browser from even parsing the html in the tag?Stavropol
@Webnet the idea is that you set the type to "text/html", and as the browser doesn't know what to make of it, it'll just ignore the contents of the script tag.Quarterly
M
8

Why not just load your templates in a hidden element and then use $(template).clone()? That saves a lot of escaping headaches. I can't speak to performance on .clone() vs the <script> approach, but I can tell you that extra script tags are a performance penalty and just generally make code muddy.

Why?

  • Even though you have a snazzy escaping utility, mistakes will still be made, and they'll be that much harder to read through. Plus if you have to work in a team situation, especially if people roll on/roll off the project, it may not be easily understandable.

  • you could create a pointer object, say, templates = {}, and load it up with jquery object pointers to your clone-able elements like so:

     templates = {};
     templates.message = $("#templates .message");
     templates.dialog = $("#templates .dialog");
    

now all you have to do to create a new template is:

var newDialog = templates.dialog.clone();

You could make a wrapper function to accept params, and then add these with newDialog.find("title").html(title), newDialog.find("message").html(message), etc.

Again, from a performance perspective, I don't know which is faster, as i don't have time to test right now. But I know that using sanctioned methods is generally better when working on a codebase large enough to require templates... its inevitable that other people will be involved eventually, and the more you have to be around to explain things, the less time you have to do your own badass coding.

Another important aspect of performance is timing... if you are experiencing performance delays, you should make sure to break up your chunks of lengthy executable code by using setTimeout. It creates a new stack and lets the browser paint what it's already processed up to the point just before the new stack is created. This helps immensely when dealing with visual delays as part of a performance issue (typically the most common performance issue noted, especially by non-coders). If you want some more info on that, send me a message and I'll gather up some resources. Limited time right now, putting out fires at work. :)

Muff answered 22/11, 2010 at 20:9 Comment(9)
The purpose of a template is to easily insert data into it. Cloning a DocumentFragment would make that process immensely painful. I can generate html from a template in one line of code.Apocarp
.clone() is a deep method; how would it be painful?Muff
how would you insert data into the markup without doing it one element at a time?Apocarp
compare your example above to Mustache.to_html(templates.dialog, { title: title, message: message })Apocarp
With this approach you can't use id-attributes anymore. They are not unique after cloning.Fortuneteller
this question should be closed because it's suuuuuper irrelevant now that there are 10 zillion templating solutions. Even my answer is 3.5 years old.Muff
Not only does this break id-attributes as stated above, there is also a risk of scripts seeing contents of the hidden element as part of the DOM and operate on them. Not to mention search engines penalizing your site for hiding content from the user.Caldeira
See my answer above. This is mega old. Cloning is a terrible way to create new nodes now that more performant solutions are available.Muff
Besides that, using an ID in a template is a bad idea for obvious reasons, anyway... so "breaking IDs" is not really a relevant concern when it comes to templating. Mustache, Underscore, and any of the larger frameworks (I prefer React) have solved this problem a million times over. Please, please disregard my original answer above. Speaking of that, there really ought to be a way to rid stackoverflow of outdated question/answer articles. Is there?Muff
T
4

I have recently done this excercise and although the <script> tag approach seems a bit hackish, I accepted this as good solution and opted for my own version (John Resigs version is obviosly really good, but I went for my own easily understandable for my own brain version)

My version is a basic template and replacement using replacable values in the form ##VALUE##

TEMPLATE: (single item template or row template)

<script type="text/html" id="ItemTemplate">
<table>
  <tr>
    <td>##LABEL1##</td>
    <td>##VALUE1##</td>
  <tr>
</table>
</script>

CONTENT CONSTRUCTION FUNCTION:

function constructFromTemplate(content, values, appendTo) {
    var modifiedHtml = content;
    modifiedHtml = modifiedHtml.replace(new RegExp('__', 'g'), '##');

    $.each(values, function (n, v) {
        modifiedHtml = modifiedHtml.replace(new RegExp('##' + n + '##', 'g'), v);
    });

    if (appendTo != null) 
    {
        $(appendTo).append(modifiedHtml);
        //initializePageElements();
    }

    return modifiedHtml;
}

USAGE

The content will be returned from the function and/or you can set the appendTo parameter set the elementID to automatically append the content. (set null to not append)

The replacable values are just added as a dynamic object where the object names are the replaceable items.

var theContent = constructFromTemplate(ItemTemplate, { LABEL1: 'The Label 1 content', LABEL2: 'The Label 2 content' }, null);

note: I have commented out //initializePageElements();, this is used to initialize jQuery plugins, styles on the template.

Only inline styles seem to work when inserting the content into the DOM

Transnational answered 18/11, 2010 at 20:57 Comment(1)
Just out of curiosity: what would that approach be? :)Quarterly
H
2

look at https://github.com/inspiraller/STQuery

STQuery uses all of the same method names as jquery but instead of manipulating elements on the dom, it works directly on the string:

var strTemplate = '<div id="splog"><h1>lorem ipsum</h1><div class="content">lorem ipsum</div></div>';

var ST = STQuery(strTemplate);

ST.find('h1').html('Hello');
ST.find('.content').html('World!');

var strTemplateUpdated = ST.html();

This keeps logic seperate from the template, ie unobtrusive html templates.

The advantages over jquery is that STQuery doesn't have to write to the DOM first, which means you could use web workers or do all your template manipulation on the server. Note: as of this message, stquery has only been written in javascript so would need to be converted to the server side language of choice.

Heathen answered 20/7, 2011 at 15:18 Comment(0)
A
1

I've tried many different techniques for this over the past year, and I agree that the script trick feels a bit wrong but I think it's the best we have.

Any template that needs to be present when the page loads has to be part of the DOM, period. Any attempt at storing them elewhere and loading them creates a noticeable lag.

I've written some template helpers that allow me to insert the necessary templates on the page, while still making it possible to lazy-load them via AJAX when needed. I load all of the templates on the page into a variable on page load, which makes it a little easier to reference.

I would certainly like to hear how others have tackled this issue.

Apocarp answered 18/11, 2010 at 20:56 Comment(5)
I agree that the ideal scenario is the templates being part of the webpage already. One thing I'm looking into is maybe use only one script tag to load all templates, instead of having one per template. Another optimization I'm thinking of is having a Python script bundle all the templates together into a .js file, and minify it. That's probably the optimum way of doing it, but it'd make development a pain in the ass.Quarterly
@Quarterly There's a couple downsides to what you're talking about, though. If you want to combine all the templates into one script section, then you need to encode them for javascript and write each one to a variable or something, which would look even uglier. Unless you're thinking about wrapping them in a parent container, in which case I don't see the benefit over multiple script tags.Apocarp
@Quarterly You can't really minify HTML, either. It would just make it look uglier, but you won't save much space. Better to keep it readable, IMO.Apocarp
Actually, I've since found there are tools, like Jammit that convert the templates to properly escaped JavaScript strings, wraps them in a function that calls the renderer and places them in a namespace. I'm trying to extend Django-Assets to do the same.Quarterly
@Quarterly Wow, Jammit looks awesome. Thanks for the heads up.Apocarp
P
1

I used script successfully with my framework jquery pure html templates

Regarding of the best practices, please have a look on the new interface of twitter, using one page for everything and only routing internally via "#!/paths".

Using single page website seams to be the next big step for web applications, personally I like to call it web 3.0 :) It will also eliminate problem with having all the same templates on each page - you will have only one page.

Psych answered 19/11, 2010 at 23:36 Comment(0)
T
0

In asp.net mvc I often pack my common templates in a partial view which I can include where I need it. That way I do not need to repeat my templates all over the place.

Another approach is to have your templates in a separate files. Like newslist.tmpl.html which allows you to load the template with ajax. Considering this can be done in parallell with the loading of data it shouldn't slow down you application, as it most likely is faster than the data call anyway.

Thao answered 22/11, 2010 at 21:16 Comment(0)

© 2022 - 2024 — McMap. All rights reserved.