So I have a compositeView. CompositeView is an "ul" element with base first "li" element and a collection of another "li" elements. My objective is to insert each rendered child collection of elements after base "li" element.
My views code
var
_NavItem = Marionette.ItemView.extend({
tagName: 'li',
template: function (serialized_model) {
return _.template('<a href="/"><span class="<%= name %>"><%= name %></span></a>')(serialized_model);
}
});
var
_NavComposite = Marionette.CompositeView.extend({
tagName: 'li',
className: 'header',
childView: _NavItem,
initialize: function () {
this.collection = new Backbone.Collection(this.model.attributes.items);
},
template: function (serialized_model) {
return _.template('<%= name %>')(serialized_model);
},
attachHtml: function(collectionView, childView){
collectionView.$el.append(childView.el);
}
});
var
_NavigationView = Marionette.CollectionView.extend({
tagName: 'ul',
childView: _NavComposite
});
and in fact this code will render structure
ul
li (base0) /li
li /li (li of collection)
li /li (li of collection)
...
li (base1) /li
li /li (li of collection)
li /li (li of collection)
...
li (base2) /li
li /li (li of collection)
li /li (li of collection)
...
/ul
but when I start this nothing happend. If I change code to
attachHtml: function(compositeView, childView){
compositeView.$el.append(childView.el);
}
it works fine, but this render another structure, that I want
ul
li (base0)
li /li (li of collection)
li /li (li of collection)
...
li /li (li of collection)
/li
li (base1)
li /li (li of collection)
li /li (li of collection)
...
li /li (li of collection)
/li
...
/ul
Structure of data
[0: { id: 1, name: 'Base li name 1', items: [
0: {id: 2, name: 'Li child 1'},
1: {id: 3, name: 'Li child 2'}
]},
1: { id: 4, name: 'Base li name 2', items: [
0: {id: 5, name: 'Li child 3'},
1: {id: 6, name: 'Li child 4'}
]}
...
]
Because of the view wrappers generated by Backbone.View, there is no way to get exactly the structure you want.You could at best have multiple li's each with li (base) and sibling li (collection) items, but they would exist in a second level list. Like this,
<ul>
<li>
<ul>
<li>
composite0.model.name
</li>
<li>
childView0.model.name
</li>
.
.
.
<li>
childViewN.model.name
</li>
</ul>
</li>
.
.
.
<li>
<ul>
<li>
compositeN.model.name
</li>
<li>
childView0.model.name
</li>
.
.
.
<li>
childViewN.model.name
</li>
</ul>
</li>
</ul>
I think all you really need is one CompositeView, and you can leverage the CompositeView template to get the effect you're looking for:
var _NavItem = Marionette.ItemView.extend({
tagName: 'li',
template: function (serialized_model) {
return _.template('<a href="/"><span class="<%= name %>"><%= name %></span></a>')(serialized_model);
}
});
var _NavBaseListView = Marionette.CompositeView.extend({
tagName: 'ul',
className: 'header',
childView: _NavItem,
template: function (serialized_model) {
return _.template('<li><%= name %></li>')(serialized_model);
},
attachHtml: function(collectionView, childView){
collectionView.$el.append(childView.el);
}
});
The template on the CompositeView will return
<li>
composite.model.name
</li>
and when attachHtml
in the CompositeView is invoked, the childView
, which is another <li>
will simply be appended below the base <li>
described in the CompositeView template. (BTW, you don't have to override attachHtml
at all, since collectionView.$el.append
is the default behavior [well sort of, because it buffers the children and then appends the group, but it's the same result]).
At the end you'll end up with
<ul>
<li>
composite.model.name
</li>
<li>
childView0.model.name
</li>
.
.
.
<li>
childViewN.model.name
</li>
</ul>
In fact this is one of the reasons CompositeView was built in the first place, see Composite Views: Tree Structures, Tables, And More, see the Grid Views part.