External template in Underscore
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 staticdir
- 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.
This mixin allows you to render external template using Underscore in very simple way: _.templateFromUrl(url, [data], [settings])
. Method API is almost the same as Underscore's _.template(). Caching included.
_.mixin({templateFromUrl: function (url, data, settings) { var templateHtml = ""; this.cache = this.cache || {}; if (this.cache[url]) { templateHtml = this.cache[url]; } else { $.ajax({ url: url, method: "GET", async: false, success: function(data) { templateHtml = data; } }); this.cache[url] = templateHtml; } return _.template(templateHtml, data, settings);}});
Usage:
var someHtml = _.templateFromUrl("http://example.com/template.html", {"var": "value"});