External template in Underscore
I use Underscore template. It is possible to attach a external file as template?
In Backbone View I have:
textTemplate: _.template( $('#practice-text-template').html() ),
initialize: function(){
this.words = new WordList;
this.index = 0;
this.render();
},
In my html is:
<script id="practice-text-template" type="text/template">
<h3>something code</h3>
</script>
It works well. But I need external template. I try:
<script id="practice-text-template" type="text/template" src="templates/tmp.js">
or
textTemplate: _.template( $('#practice-text-template').load('templates/tmp.js') ),
or
$('#practice-text-template').load('templates/tmp.js', function(data){ this.textTemplate = _.template( data ) })
but it did not work.
Here is a simple solution:
var rendered_html = render('mytemplate', {});
function render(tmpl_name, tmpl_data) {
if ( !render.tmpl_cache ) {
render.tmpl_cache = {};
}
if ( ! render.tmpl_cache[tmpl_name] ) {
var tmpl_dir = '/static/templates';
var tmpl_url = tmpl_dir + '/' + tmpl_name + '.html';
var tmpl_string;
$.ajax({
url: tmpl_url,
method: 'GET',
dataType: 'html', //** Must add
async: false,
success: function(data) {
tmpl_string = data;
}
});
render.tmpl_cache[tmpl_name] = _.template(tmpl_string);
}
return render.tmpl_cache[tmpl_name](tmpl_data);
}
Using "async: false" here is not a bad way because in any case you must wait until template will be loaded.
So, "render" function
- allows you to store each template in separate html file in static dir
- is very lightweight
- compiles and caches templates
- abstracts template loading logic. For example, in future you can use preloaded and precompiled templates.
- is easy to use
[I am editing the answer instead of leaving a comment because I believe this to be important.]
if templates are not showing up in native app, and you see HIERARCHY_REQUEST_ERROR: DOM Exception 3
, look at answer by Dave Robinson to What exactly can cause an "HIERARCHY_REQUEST_ERR: DOM Exception 3"-Error?.
Basically, you must add
dataType: 'html'
to the $.ajax request.
EDIT: This answer is old and outdated. I'd delete it, but it is the "accepted" answer. I'll inject my opinion instead.
I wouldn't advocate doing this anymore. Instead, I would separate all templates into individual HTML files. Some would suggest loading these asynchronously (Require.js or a template cache of sorts). That works well on small projects but on large projects with lots of templates, you find yourself making a ton of small async requests on page load which I really dislike. (ugh... ok, you can get around it with Require.js by pre-compiling your initial dependencies with r.js, but for templates, this still feels wrong to me)
I like using a grunt task (grunt-contrib-jst) to compile all of the HTML templates into a single templates.js file and include that. You get the best of all worlds IMO... templates live in a file, compilation of said templates happen at build time (not runtime), and you don't have one hundred tiny async requests when the page starts up.
Everything below is junk
For me, I prefer the simplicity of including a JS file with my template. So, I might create a file called view_template.js which includes the template as a variable:
app.templates.view = " \
<h3>something code</h3> \
";
Then, it is as simple as including the script file like a normal one and then using it in your view:
template: _.template(app.templates.view)
Taking it a step further, I actually use coffeescript, so my code actually looks more like this and avoid the end-of-line escape characters:
app.templates.view = '''
<h3>something code</h3>
'''
Using this approach avoids brining in require.js where it really isn't necessary.