I'm trying to render the response from an API (JSON) with Backbone.Marionette.ItemView
. Not sure why it is not working.
I'm using marionette v2.4.7 (on purpose);
Here is the handlebars template:
<script id="feed-post" type="text/x-handlebars-template">
{{#each posts}}
<a href="#"><img src="{{author.image_url}}" alt=""></a>
<a href="#"><p>{{author.name}}</p></a>
<span>TODO TIMESTAMP</span>
<p>{{body}}</br>{{topic_type}}</p>
{{/each}}
</script>
Here is my full app.js (all Backbone logic in this file);
// Model
var Post = Backbone.Model.extend({
defaults: {
authorPic: 'Unknown',
authorName: 'Unknown',
timestamp: 'Unknown',
body: 'Not available',
comments: '0'
}
});
// Collection
var Posts = Backbone.Collection.extend({
model: Post,
url: 'http://localhost:4321/blogposts',
initialize: function(){
this.fetch();
}
});
// View
var PostView = Marionette.ItemView.extend({
el: '#content',
template: Handlebars.compile($("#feed-post").html()),
});
//Config
var chunkPosts = new Posts();
var myview = new PostView({collection: chunkPosts});
Also, I tried to console.log
the view and it looks like the models are in there.
This answer is tailored to Marionette v2.4.7. LayoutView
and ItemView
were merged and renamed to View
back in v3.0.0.
From the doc on ItemView
:
Rendering this view will convert the
someCollection
collection in to theitems
array for your template to use.
You are using posts
in your template while the doc says it will be called items
.
As a reference, here's the exact code doing that in the ItemView
source:
// Serialize the model or collection for the view. If a model is // found, the view's `serializeModel` is called. If a collection is found, // each model in the collection is serialized by calling // the view's `serializeCollection` and put into an `items` array in // the resulting data. If both are found, defaults to the model. // You can override the `serializeData` method in your own view definition, // to provide custom serialization for your view's data. serializeData: function() { if (!this.model && !this.collection) { return {}; } var args = [this.model || this.collection]; if (arguments.length) { args.push.apply(args, arguments); } if (this.model) { return this.serializeModel.apply(this, args); } else { return { items: this.serializeCollection.apply(this, args) }; } },
The last lines show that for a collection, a new object with items
as the only attribute is returned.
It's mentioned that you can override the serializeData
function, more information and examples are available in the doc.
You still need to call render
on the view and since the collection's fetch
is async, you won't have items out of the box so you should wire a listener.
First, don't fetch in the initialize
of a collection, it makes the collection pretty much useless for any other use-case.
var Posts = Backbone.Collection.extend({
model: Post,
url: 'http://localhost:4321/blogposts',
});
Listen for the collection sync
event, then fetch within the view instead.
var PostView = Marionette.ItemView.extend({
el: '#content',
template: Handlebars.compile($('#feed-post').html()),
initialize: function () {
this.listenTo(this.collection, 'sync', this.render);
this.collection.fetch();
},
});
Marionette even offers collectionEvents
:
var PostView = Marionette.ItemView.extend({
// ...snip...
collectionEvents: {
"sync": "render"
}
// ...snip...
});