Reputation: 10653
I know that there are a few questions around regarding this, but the answers are not very clear for me to implement. That's why I'm asking this question again so I can have a clear and simple answer.
I've always had trouble with Collection
in Backbone, especially populating it with JSON data.
I can't seem to get the collection to render in the View, even though in firebug I can see that, it's being fetched from the server, but the screen is still empty.
Also, when I do a console.log('callers: ', this.callerList)
, it returns an object with models=[0]
. But when I expand the object, models
is full of data from the JSON file. What's going on with Backbone and it's confusing results?
Can someone please explain to me how to do it? I've been battling this for ages and I can't get my head around it.
Many Thanks
JS:
(function($, window) {
// model
var CallerModel = Backbone.Model.extend({});
// collection
var CallersList = Backbone.Collection.extend({
model: CallerModel,
url: 'js/json/callers.json'
});
// view
var CallerView = Backbone.View.extend({
el: '.caller-app',
template: _.template($('#callers-template').html()),
initialize: function() {
this.callerList = new CallersList();
this.callerList.fetch();
this.callerList.bind('reset', this.render);
console.log('caller: ', this.callerList);
},
render: function(e) {
console.log('RENDER');
_.each(this.collection.models, function(caller) {
this.$el.append(this.template(caller.toJSON()));
console.log('callerList: ', caller);
}, this);
return this;
}
});
// start
var callerView = new CallerView();
}(jQuery, window));
HTML:
<!-- wrapper -->
<div class="wrapper">
<h1>Missed Calls App</h1>
<div class="caller-app"></div>
</div>
<!-- wrapper -->
<!-- templates -->
<script type="text/template" id="callers-template">
<div class="caller">
<h2><%= title %> <%= name %> called</h2>
<h3>From <%= agency %></h3>
<p>When: <%= when %></p>
<p>Contact: <%= tel %></p>
<p>Says:"<%= message %>"</p>
</div>
</script>
<!-- templates -->
JSON:
[
{
"id": 1,
"title": "Mrs",
"name": "Mui",
"agency": "Ryuzanpaku Dojo",
"when": "evening",
"tel": "0207 123 45 67",
"message": "Check your availability"
},
{
"id": 2,
"title": "Mrs",
"name": "Shigure",
"agency": "Ryuzanpaku Dojo",
"when": "evening",
"tel": "0207 123 45 67",
"message": "Check your availability"
}
]
Upvotes: 3
Views: 162
Reputation: 10993
You haven't actaully assigned a collection to your CallerView, in addition when you iterate though the collection you should be using this.collection.models
instead of this.model.models
For example when initializing you caller list initialize: function() {
initialize: function() {
this.collection = new CallersList();
this.collection.fetch();
this.collection.bind('reset', this.render);
}
And when rendering
render: function(e) {
_.each(this.collection.models, function(caller) {
this.$el.append(this.template(caller.toJSON()));
}, this);
return this;
}
Here's a link to a jsbin
Some additional points
In general you want to decouple your code as much as possible. To this end it is probably better to declare and initialize your collection outside of your view and then pass it in. This also has the advantage of making your code more reusable, for example say you wanted to render a second list of calls (let say recent calls), you can now just create a second instance of your view passing in a collection and element.
For example
var missedCalls = new CallersList();
var callerView = new CallerView({collection : missedCalls, el: '#missedCalls' });
missedCalls.fetch();
var recentCalls = new CallerList(); //you probably want to use a different url
var recentCallersView = new CallerView({collection : recentCalls, el:'#recentCalls'});
recentCalls.fetch();
Another point worth mentioning, currently you are rendering all items in your collection for each fetch, including any that have been already rendered. You might want either empty your el
before rendering or listen to the add
event instead and render each item individually as it's added. In addition it's worth pointing out that fetch
isn't really meant to be used to load data on page load, from the documentation
Note that fetch should not be used to populate collections on page load — all models needed at load time should already be bootstrapped in to place. fetch is intended for lazily-loading models for interfaces that are not needed immediately: for example, documents with collections of notes that may be toggled open and closed.
Upvotes: 2