Use Handlebars.js with Backbone.js
class Mustachio extends Backbone.View
render: (template_id, context) ->
@templates[template_id].call @, context
@prepare = ->
templates = {}
$('script[type="text/x-handlebars-template"]').each ->
raw_template = this.textContent
raw_template = this.innerHTML unless raw_template # IE 8
templates[this.id] = Handlebars.compile(raw_template)
@::templates = templates
window.Mustachio = Mustachio
$ ->
Mustachio.prepare()
Let's dissect.
Mustachio.prepare()
crawls the page, finds all the handlebars templates, compiles and caches them. This allows render to simply do a lookup and then call the template with the context.
With your views, you can extend the Mustachio class:
class IdeaList extends Mustachio
events:
"click .delete": 'delete'
delete:
@model.delete()
@remove()
render:
html = super('idea-item', context)
@options.parent.$el.append html
@setElement("#idea-#{@model.get('id')}")
Since Mustachio is the parent class, calling super looks up the cached template, renders it and returns the rendered HTML for use. Alternatively, if there is nothing else you need to do, just omit the render
method from your model and just allow render to be called on the parent class.
@tjsingleton recommended one additional performance gain for the page load. Instead of crawling and compiling at page load, lazy compile the templates on first request. This would look like the following (with duplicate code removed for brevity):
class Mustachio extends Backbone.View
templates: {}
lazyCompileFactory: (template_id, raw_template) ->
@templates[template_id] = (context) =>
compiled_template = Handlebars.compile(raw_template)
@templates[this.id] = compiled_template
compiled_template(context)
@prepare = ->
$('script[type="text/x-handlebars-template"]').each (i, item) =>
raw_template = item.textContent
raw_template = item.innerHTML unless raw_template # IE 8
@::lazyCompileFactory(item.id, raw_template)
Here's the two versions in a gist for easier comparison: