Backbone JS Views are very “helpful” in that they always creates a DOM node for you, with a configurable tag, id and class. This is very nice and accommodating, but I’m finding that it creates an unfortunate situation: the DOM node created by the View is a hidden template.
This became obvious to me on our current project, where we are sharing Mustache templates between the front and back ends. With Backbone, when you want a DOM that looks like this:
<section class="note">
<textarea>
...
</textarea>
<input type="button" class="save-button" value="Save">
<input type="button" class="cancel-button" value="Cancel">
</section>
you end up creating templates that look like this:
<textarea>
{{& content}}
</textarea>
<input type="button" class="save-button" value="Save">
<input type="button" class="cancel-button" value="Cancel">
But now your template is tied to the secret root-node template on your Backbone view, which will need to be duplicated on the server side. So much for DRY encapsulation!
I don’t see an immediately obvious way to address this, except by using setElement() with the rendered template at render time, but this brings other problems with it, like having to replace the newly rendered subtree in the DOM after every render().
How have you addressed this issue?
It’s an interesting question. I’ve never had to solve this particular problem before, but I tried out a few options and I think I found one that I like.
First, here’s the code:
Essentially you define a base view that expects every derived view to have a
templateproperty, or to take atemplateas an argument in the options hash. The template can be a string, a DOM node or a jQuery/Zepto -wrapped DOM node. The view assumes the root node of the template as itsel, and redefines thetemplateproperty as the contents of the root node.You would use it as a normal view:
The
elproperty is available from the get-go, and it’s not detached and reattached on re-render. The only exception to the normalBackbone.Viewbehavior is that if you’ve defined theid,cssClassortagNameproperties or arguments, they will be ignored, because the template provides the root element.This is not extensively tested, but seems to pass most simple test cases. The only drawback that I can think of is that the
templatehtml string is stored on every view instance (instead of the prototype) and wastes precious bytes of memory, but that shouldn’t be hard to solve either.Here is a working demo on JSFiddle.