Reputation: 2385
I have a Layout view, with a region comprising a select input.
//template
<div class="col-xs-12">
<select name="type" id="drop" class="select"></select>
</div>
I have a LayoutView which defines the following region and assigns a collection view to populate the select menu with options.
//layout
Backbone.Marionette.LayoutView.extend({
regions: {drop: "#drop"},
onRender: function() {
this.getRegion("drop").show(new (Marionette.CollectionView.extend({
childView: FieldView
}))(collection: fieldCollection)));
}
}
FieldView
and fieldCollection
work fine, but I have a problem. When rendering, the collection sub-view wraps the options in a div tag, preventing the select menu from working properly.
//Rendered HTML
<select name="type" id="drop" class="select">
<div>
<option value='1'>Option 1</option>
<option value='2'>Option 2</option>
<option value='3'>Option 3</option>
</div>
</select>
Any advice for how to get rid of that pesky div tag? And shouldn't the subview's el
be scoped to the select element itself, by virtue of the region?
Upvotes: 0
Views: 378
Reputation: 5053
Since yours is a common enough problem, the extra div functionality is often debated. See, for example, this very interesting issue.
Unfortunately, Backbone nor Marionette Views are aware of their parent view, even if that parent view is a LayoutView. In fact, Marionette inherited the wrapper behavior from Backbone, and in the majority of cases its the most common-sense structure for a view to have.
el
, Live dangerouslyYou can take the more treacherous route of assigning your Region's element to the CollectionView's el
, which I described in this Answer. What I suggest there, is to override the Region's .attachHtml()
method to insert the contents (and not the el
) of the sub-view directly into the el
of the Region, and, most importanlty, setting the sub-view's el
to the Region's el
using view.setElement()
. But read the warnings there carefully. The events between the two views will be shared! You can't avoid that.
Personally, I advocate to work with, and not against, Backbone/Marionette on this one. I understand that you may have very good reason to want the <select/>
element inside your LayoutView. However, if you can live without that element in there, I can offer you a very simple and quick fix: You can use whatever (proper) HTML element you want for a view's wrapper. So your .show()
can look like this:
onRender: function() {
this.getRegion("drop").show(new (Marionette.CollectionView.extend({
tagName: "select",
attr: {
name:"type"
},
id: "drop",
className: "select",
childView: FieldView
}))(collection: fieldCollection)));
}
All I did up there was change the vanilla <div/>
el
of the view, to
<select name="type" id="drop" class="select"></select>
Don't forget, you'll want to assign a new element to your Region. Let's the take the original <div/>
enclosing the <select/>
, for instance,
<div class="col-xs-12" id="field-region">
</div>
<select/>
element in your LayoutViewThe <select/>
statement is not the el
of your CollectionView. This may not bother you, but chances are, at some point you'll do something like $("#drop").val()
in your LayoutView. The good news is that you can natively access <select/>
since its the el
of the CollectionView you're passing in. The cost is that you'll want to keep a reference of that view. Something like,
onRender: function() {
this.fieldView = new Marionette.CollectionView.extend({
tagName: "select",
attr: {
name:"type"
},
id: "drop",
className: "select",
childView: FieldView
});
this.getRegion("drop").show(this.fieldView(collection: fieldCollection));
},
onSelectOption: function () {
console.log(this.fieldView.$el.val());
}
Upvotes: 1