Using Backbone and Marionette, I've created a new layout that goes into the main content div on my page. The layout looks like this:
<div id='dash-sidebar'>
<div id='dash-profile'></div>
<div id='dash-nav'></div>
</div>
<div id='dash-content'></div>
The issue is that when I render the layout, Backbone automatically wraps it in a div before putting it into the main content div like this:
<div id='main-content'>
<div>
<div id='dash-sidebar'>
<div id='dash-profile'></div>
<div id='dash-nav'></div>
</div>
<div id='dash-content'></div>
</div>
</div>
I know that I can change the element with tagName, but is it possible to avoid wrapping the template altogether and just insert it directly into the main content div on the page?
I wanted to achieve pretty much the same thing. I'd like to have all the HTML markup in my templates and let Backbone do the rest. So I wrote the following snippet which removes the extra 'div'.
First, you set the tagName to 'detect' and then after the first render you detect the tagName of the first element inside your view. Obviously this only works when you provide your own wrapper in your template.
Template:
However, I've just played around with it a little - if anybody sees any problems that this approach could cause (performance, memory, zombies, etc) I'd be very open to learn about them.
BTW, this could probably easily packaged into a plugin.
EDIT3: Warning! This answer may be out of date. I received a comment that this answer no longer works and have not had the time to investigate (I personally do not use this method).
I like to use Twitter/Bootstrap as my UI library and was having some issues with table styling because of the default tag wrapping (specifically a
<div>
between my<tbody>
and my<tr>
s).After some digging, I found something in the Marionette docs on the
Region
about how theView
attaches theel
. Backbone builds theel
from variousView
attributes and keeps the built element up to date so it can be rendered at any time. So I figured, ifview.el
is the parent, why not just use the HTML contents? Marionette also provides a way to create a customRegion
I was able to get everything running by creating a custom
Region
with an overriddenopen
function. That way I can specify which regions I want to wrap with a tag and those that I do not. In the following example snippet, I create my custom non-wrappingRegion
(NowrapRegion
) and use it in myLayout
(MyLayout
) for my<tbody>
(the views I pass in my real program create<tr>
s).BOOM! Wrapping when I want it and none when I don't.
EDIT: This seems to affect
events
applied at the*View
level. I haven't looked into it yet, but be warned that they don't seem to be getting triggered.Whether this is the "right" way to do it or not, I am not sure. I would welcome any feedback from @derick-bailey should he see this.
EDIT2: @chris-neale suggested the following, I have not verified this yet but it seems sound. Thanks!
Each Backbone View must be represented by a single element. Your first HTML block has two elements, which is why it cannot be represented by a view without first wrapping it in an outer div.
Could you refactor your Layout to include the
main-content
area as well? Then the Layout'sel
would correspond to the entire outer div.Another thing to try would be using Backbone.View's setElement() method to override the creation of the outer div, and manually inject the HTML that you want for the element in a View. Something like:
I'm not sure how this would work if you passed in HTML that had two parent elements instead of just one, however.
UPDATE: Marionette.Layout is an extension of the Backbone view, so this is the normal behavior, see backbone documentation:
So my previous answer had nothing to do with your problem, sorry.
Update:
Found an issue 546 in Backbone gitHub on this subject (wich was closed as wontfix), jashkenas posted this comment to explain why it is not easy to implement: