Reputation: 3920
**UPDATE: The problem probably involves the tour-template as I've discovered that it thinks the 'name' attribute is undefined. This leads me to think that it's not an array being passed on to the ToursView, but for some reason a string. **
After studying similar questions on StackOverflow:
How to handle nested CompositeView using Backbone.Marionette?
Nested collections with Backbone.Marionette
... and Derick Bailey's excellent blog's on this subject:
http://lostechies.com/derickbailey/2012/04/05/composite-views-tree-structures-tables-and-more/
... including the JSFiddle's:
http://jsfiddle.net/derickbailey/AdWjU/
I'm still having trouble with a displaying the last node of a nested CollectionView of CompositeViews. It is the final CollectionView within each CompositeView that is causing the problem.
CollectionView {
CompositeView{
CollectionView {} //**<-- This is the troublemaker!**
}
}
NOTE: I have already made a point of creating a valid Backbone.Collection given that the collection passed on to the final, child CollectionView is just a simple array.
Data returned from the api to ToursList:
[
{ "id": "1",
"name": "Venice",
"theTours": "[
{'name': u'test venice'},
{'name': u'test venice 2'}
]"
},
{ "id": "2",
"name": "Rome",
"theTours": "[
{'name': u'Test rome'}
]"
},
{ "id": "3",
"name": "Dublin",
"theTours": "[
{'name': u'test dublin'},
{'name': u'test dublin 2'}
]"
}
]
I'm trying to nest these in a dropdown where the nav header is the 'name' (i.e. Dublin), and the subsequent li 's are the individual tour names (i.e. 'test dublin', 'test dublin2', etc.)
Tour Models and Collections
Tour = TastypieModel.extend({});
ToursGroup = TastypieCollection.extend({
model: Tour
});
ToursByLoc = TastypieModel.extend({});
ToursList = TastypieCollection.extend({
model: ToursByLoc,
url:'/api/v1/location/',
});
Tour Views
TourView = Backbone.Marionette.ItemView.extend({
model: Tour,
template: '#tour-template',
tagName: 'li',
});
ToursByLocView = Backbone.Marionette.CompositeView.extend({
collection: ToursByLoc,
template: '#toursByLoc-template',
itemView: TourView,
itemViewContainer: '#ind',
initialize: function(){
//As per Derick Bailey's comments regarding the need to pass on a
//valid Backbone.Collection to the child CollectionView
//REFERENCE: https://stackoverflow.com/questions/12163118/nested-collections-with-backbone-marionette
var theTours = this.model.get('theTours');
this.collection = new ToursGroup(theTours);
console.log(this.model.get('name'));
console.log(theTours);
//To test the output --> I get:
//Venice
//[{'subtitle': u'ex. These prices include... but not...', 'description': u'Please enter the tour description here', 'start_time': datetime.time(2, 34, 24), 'adult_price': Decimal('123'), 'important': u'ex. Please contact us to negotiate a price if you want to book the Fiat for 1 person only.', 'teenager_student_price': Decimal('123'), 'child_price': Decimal('123'), 'under_6_price': Decimal('123'), 'location_id': 1, 'id': 1, 'name': u'test venice'}, {'subtitle': u'ex. These prices include... but not...', 'description': u'Please enter the tour description here', 'start_time': datetime.time(20, 4, 57), 'adult_price': Decimal('222'), 'important': u'ex. Please contact us to negotiate a price if you want to book the Fiat for 1 person only.', 'teenager_student_price': Decimal('222'), 'child_price': Decimal('222'), 'under_6_price': Decimal('222'), 'location_id': 1, 'id': 2, 'name': u'test 2'}] main.js:64
//Rome
//[{'subtitle': u'ex. These prices include... but not...', 'description': u'Please enter the tour description here', 'start_time': datetime.time(1, 28, 25), 'adult_price': Decimal('123'), 'important': u'ex. Please contact us to negotiate a price if you want to book the Fiat for 1 person only.', 'teenager_student_price': Decimal('333'), 'child_price': Decimal('333'), 'under_6_price': Decimal('333'), 'location_id': 2, 'id': 3, 'name': u'test rom1'}] main.js:64
//Dublin
//[]
this.collection = new ToursGroup(theTours);
}
});
ToursListView = Backbone.Marionette.CollectionView.extend({
itemView: ToursByLocView,
});
Templates
<script id="tour-template" type="text/template">
<%= name %> //<-- THIS IS GIVING ME ISSUES
</script>
<script id="toursByLoc-template" type="text/template">
<li class="nav-header"><%= name %></li>
<div id="ind" class="indTours"></div>
<li class="divider"></li>
</script>
<script id="tours-template" type="text/template">
<%= name %>
</script>
Upvotes: 3
Views: 2536
Reputation: 72868
I don't think this is the problem, but this should be changed:
itemViewContainer: '#ind'
in your CompositeView definition. This is bad / invalid / may produce unexplainable results. The DOM should only container one instance of an HTML element with any given id
. In this case, you have a <div id="ind"></div>
for every CompositeView instance.
You should change this to a css class, and use the class selector for the itemViewContainer
instead.
...
I built a JSFiddle with your code, and it appears to work: http://jsfiddle.net/derickbailey/QPg4D
what results are you seeing in your app? what are you expecting to see instead?
...
Look at the way your data is coming back:
"theTours": "[
{'name': u'test venice'},
{'name': u'test venice 2'}
]"
this is technically valid JSON, but it's going to return a string that looks like an array, instead of an actual array.
In my JSFiddle I had to correct this:
"theTours": [
{'name': 'test venice'},
{'name': 'test venice 2'}
]
Notice that I removed the " and " around the [ ] and I also removed the "u" in front of the string values.
It may be that your server is improperly serializing the data to a JSON document, and sending back this badly formatted doc.
Upvotes: 4