Skip to content

Instantly share code, notes, and snippets.

@paton
Last active December 22, 2015 08:18
Show Gist options
  • Save paton/6443514 to your computer and use it in GitHub Desktop.
Save paton/6443514 to your computer and use it in GitHub Desktop.
How to include subviews in a Backbone template using handlebars
/*
How it works:
1) Pass in the parent view when rendering subviews in templates
{{v 'subview' parent=this}}
2) the 'v' handlebars helper:
- creates the child view and calls its render method
- set data-cid="CID" on the subview
- return the subviews's outerHTML, *without* deleteing the subview
3) At this point, childView's html is on the page, but the html is not attached to the view
4) In the parent view's postRender, call attachChildViews
5) attachChildViews iterates over this.childViews, which contains the view
we created in the handlebars helper. For each registered child view,
we find the (unattached) DOM element by using the data-cid attribute, and pass
the DOM el to View.Backbone.attach method of the child view. This attaches all the
events for the subview to the dom
BOOM. No more multiple initialization of views
No more postRender being called a million times
No more defining listeners in postRender
*/
// Handlebars 'v' helper
Handlebars.registerHelper('v', function(context, options) {
var viewName = context,
viewOptions = options.hash || {},
View, view, parentView, html;
var parent;
if (options.hash) {
parent = options.hash.parent;
}
if (viewOptions.context) {
viewOptions = viewOptions.context;
}
if (_.isEmpty(viewOptions)) {
viewOptions = _.clone(this);
}
View = BaseView.getView(viewName);
view = new View(viewOptions);
parentView = this._view;
if (!parentView && parent) {
parentView = parent._view;
}
// Register the child view with the parent view
var html;
if (parentView) {
parentView.registerChildView(view);
}
// Render the view
view.render();
// Attach the CID to the view's html
view.$el.attr('data-cid', view.cid);
// Return the outerHTML... don't delete view
return new Handlebars.SafeString(view.$el[0].outerHTML);
});
// Render method of the parent view...
render: function() {
var html = this.getInnerHtml();
this.$el.html(html);
this.$el.attr('data-view', this.name);
// Attach child views
this.attachChildViews();
this._postRender();
if(!this.fetching &&
(this.lazy || this.options.lazy) &&
(!this.collection && !this.model)) {
this.fetchLazy();
}
return this;
},
// attachChildViews method that was called in render()
attachChildViews: function() {
var _this = this, $el;
_.each(this.childViews, function(childView){
// Get the cid that we injected in the handlebars helper
$el = _this.$('[data-cid="'+childView.cid+'"]');
// Call Backbone.View.attach on the child view.
if ($el.data('attached') !== true) childView.attach($el);
});
},
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment