I have noticed there is a different, the way DOM been updated by Marionette comparing with Backbone. I have created two simple fiddles. One using Backbone and other one based on marionette. Both examples has a helper method call processDom and that method simply throw an error after iterating 50 times.
However in backbone example elements been appended to DOM till die() method fires. But in marionette based example DOM has not been updated at all. It would be great if someone can explain how this works. I wonder marionette internally using a virtual dom kind of a technique.
Render method in marionette example
render: function () {
var viewHtml = this.template({
'contentPlacement': 'Sydney'
});
this.$el.html(viewHtml);
this.processDom(this.$el);
this.postRender();
}
Render method in backbone example
render: function () {
var template = Handlebars.compile($('#sample-template').html());
var viewHtml = template({
'contentPlacement': 'Sydney'
});
this.$el.html(viewHtml);
this.processDom(this.$el);
this.postRender();
},
Links to fiddle examples
In general for post processing purposes you could use onRender
of Marionette.ItemView
. It's not a good practice to rewrite Marionette.ItemView.render
.
Rendering of views inside the regions for Marionette
is handled a bit different as in Backbone
case.
When you rendering Backbone.View
- your element will attach itself to the DOM's $('#search-container')
, and in render
method it will operate with already attached element so you can see the changes.
When you rendering Marionette.ItemView
with Marionette.Region.show
method, Marionette.Region
already attached to the DOM and it need to render appropriate view (in your case ItemView
) and only after that step it will attach it to the DOM and will set the ItemView
as currentView
.
You can see from source of Marionette.Region.show
that it attaches view after render
is called. In your case render
will throw error and it will never be attached to the DOM.
To understand it deeper lets look at the 2 methods which are responsible for attaching/creating views in BackboneView. Marionette uses the same method for Marionette.ItemView
.
_ensureElement: function() {
if (!this.el) { // case when el property not specified in view
var attrs = _.extend({}, _.result(this, 'attributes'));
if (this.id) attrs.id = _.result(this, 'id');
if (this.className) attrs['class'] = _.result(this, 'className');
// creating new jQuery element(tagNam is div by default) with attributes specified
var $el = Backbone.$('<' + _.result(this, 'tagName') + '>').attr(attrs);
this.setElement($el, false);
} else { // case when el property exists
this.setElement(_.result(this, 'el'), false);
}
}
And
setElement: function(element, delegate) {
if (this.$el) this.undelegateEvents();
// here is all magic
// if element is instance of Backbone.$, which means that el property not specified
// or it's already jquery element like in your example( el: $('#search_container')) with Backbone.
// this.$el will be just a jQuery element or already attached to the DOM jQuery element
// in other case it will try to attach it to the DOM.
this.$el = element instanceof Backbone.$ ? element : Backbone.$(element);
this.el = this.$el[0];
if (delegate !== false) this.delegateEvents();
return this;
},
As you can see from comments all magic is in a few lines of code, and that's why I love it.