Below I have the code for one of my modules. This is kind of spagetti-ish code, but all I want to accomplish is having a model, a collection, and render a view (using underscore templates) connecting the data from the collection to the views. I’m failing miserably. The problem I’m getting is that trying to run the last call down there to testfeed.render() tells me that render is not a function, yet it is clearly defined. I’m able to fetch that data and seemingly add it to the collection from the api. What am I doing wrong here?
// Create a new module.
var Tagfeed = app.module();
// Default model.
Tagfeed.Model = Backbone.Model.extend({
defaults : {
name : '',
image : ''
},
initialize : function(){
console.log('tagfeed model is initialized');
this.on("change", function(){
console.log("An attribute has been changed");
});
}
});
var feedCollection = Backbone.Collection.extend({
model: Tagfeed.Model,
initialize : function () {
console.log('feedcollection is initialized');
},
fetch: function () {
var thisCollection = this;
Api_get('/api/test', function(data){
$.each(data.data, function(){
thisCollection.add(this);
});
return thisCollection;
})
}
});
var test = new Tagfeed.Model({name:'test'});
var newFeedCollection = new feedCollection();
newFeedCollection.fetch();
console.log(newFeedCollection.at(0));
var testfeed = Backbone.View.extend({
el: $('#main'),
collection : newFeedCollection,
render: function( event ){
var compiled_template = _.template( $("#tag-template").html() );
this.$el.html( compiled_template(this.model.toJSON()) );
return this; //recommended as this enables calls to be chained.
}
});
testfeed.render();
EDIT * updated code from @mu is short suggestions
// Create a new module.
var Tagfeed = app.module();
// Default model.
var tagModel = Backbone.Model.extend({
defaults : {
name : '',
image : '',
pins : 0,
repins : 0,
impressions : 0
},
initialize : function(){
console.log('tagfeed model is initialized');
this.on("change", function(){
console.log("An attribute has been changed");
});
}
});
var feedCollection = Backbone.Collection.extend({
model: tagModel,
initialize : function () {
console.log('feedcollection is initialized');
},
fetch: function () {
var thisCollection = this;
Api_get('/reporting/adlift/pin_details', function(data){
thisCollection.add(data.data);
return data.data;
})
}
});
var test = new tagModel({name:'test'});
var newFeedCollection = new feedCollection();
newFeedCollection.fetch();
console.log(newFeedCollection.at(0));
var TestFeed = Backbone.View.extend({
el: $('#main'),
render: function( event ){
console.log('here');
var compiled_template = _.template( $("#tag-template").html(), this.collection.toJSON());
this.el.html( compiled_template );
return this; //recommended as this enables calls to be chained.
},
initialize: function() {
console.log('initialize view');
this.collection.on('reset', this.render, this);
}
});
//Tagfeed.testfeed.prototype.render();
var testfeed = new TestFeed({ collection: newFeedCollection });
testfeed.render();
and now when i run testfeed.render() I don’t see any error, nor do i see that console.log in the render function. thoughts?
Your problem is right here:
That makes your
testfeeda view “class”, you have to create a new instance withnewbefore you can render it:You’re also doing this inside the “class”:
That will attach
newFeedCollectionto each instance of that view and that might cause some surprising behavior. The usual way of getting a collection into a view is pass it to the constructor:The view constructor will automatically set the view’s
this.collectionto the collection you pass when building the view.Another thing to consider is that this:
is usually an AJAX call so you might not have anything in your collection when you try to render it. I would do two things to deal with this:
rendershould be able to deal with an empty collection. This mostly depends on your template being smart enough to be sensible when the collection is empty.Bind
renderto the collection’s"reset"event in the view’sinitialize:Another problem you’ll have is that your view’s
renderis trying to renderthis.model:when your view is based on a collection; you want to change that to:
You’ll need the
tagsin there so that the template has a name to refer to when looking at the collection data.Also, you should be able to replace this:
with just this:
There’s no need to add them one by one,
Collection#addis perfectly happy with an array of models.And here’s a demo with (hopefully) everything sorted out:
I had to fake the
fetchinternals but everything else should be there.