Last active
December 22, 2015 08:18
-
-
Save paton/6443514 to your computer and use it in GitHub Desktop.
How to include subviews in a Backbone template using handlebars
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
/* | |
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