backbone.js collection with overridden toJSON method
I have a Model which has two properties, which are Collections:
MainModel= Backbone.Model.extend({
defaults: {
colOne:undefined,
colTwo:undefined
},
initialize:function() {
this.set({colOne:new InnerCollection()});
this.set({colTwo:new InnerCollection()});
}
});
InnerCollection= Backbone.Collection.extend({
model: InnerModel,
});
InnerModel= Backbone.Model.extend({
...
});
I found that items ( InnerModels
) were not being removed properly from Collections colOne and colTwo. I found a Question here on Stackoverflow that seemed to explain the cause of the problem and present a solution. I provided an overridden implementation of toJSON()
on my Model:
MainModel= Backbone.Model.extend({
defaults: {
colOne:undefined,
colTwo:undefined
}
initialize:function() {
this.set({colOne:new InnerCollection()});
this.set({colTwo:new InnerCollection()});
},
toJSON: function() {
_.extend(this.attributes, {colOne: this.get('colOne').toJSON()});
_.extend(this.attributes, {colTwo: this.get('colTwo').toJSON()});
return this.attributes;
},
});
Question #1 - I'm not really sure why this would solve the problem or why I'm doing it.
Question #2 - It causes an error when I try to use the collection colOne
or colTwo
in my Views. The stack trace is:
Uncaught TypeError: Object [object Object],[object Object] has no method 'bind'
Backbone.View.extend.initializeinteractiveviews.js:646
Backbone.Viewbackbone.js:1147
childbackbone.js:1392
Backbone.View.extend.renderinteractiveviews.js:441
Backbone.View.extend.renderinteractiveviews.js:619
(anonymous function)interactiveviews.js:766
_.each._.forEachunderscore.js:76
wrapper.(anonymous function)underscore.js:961
Backbone.View.extend.renderinteractiveviews.js:758
Backbone.View.extend.renderinteractiveviews.js:452
Backbone.View.extend.renderinteractiveviews.js:619
(anonymous function)interactiveviews.js:766
_.each._.forEachunderscore.js:76
wrapper.(anonymous function)underscore.js:961
Backbone.View.extend.renderinteractiveviews.js:758
Backbone.View.extend.renderinteractiveviews.js:443
Backbone.View.extend.renderinteractiveviews.js:619
window.AppView.Backbone.View.extend.renderindex.html:73
window.AppView.Backbone.View.extend.initializeindex.html:47
Backbone.Viewbackbone.js:1147
childbackbone.js:1392
(anonymous function)index.html:97
jQuery.Callbacks.firejquery-1.7.2.js:1075
jQuery.Callbacks.self.fireWithjquery-1.7.2.js:1193
jQuery.extend.readyjquery-1.7.2.js:435
DOMContentLoaded
bind
is just the first place where I try and use the collection colOne
:
// this.collection is colOne
this.collection.bind('myEvent', this.myEventHandler);
I don't have any syntax errors, so I'm not sure how my toJSON method has broken things.
Update
This was not a problem with Backbone.js. The problem I was experiencing was down to not unbinding from an event. Consequently, although a particular View was no longer visible once the collection was empty, it was being triggered with an event to add a new item. This s why the count of the collection went up each time I removed an item from a View event.
This was not a problem with Backbone.js. The problem I was experiencing was down to not unbinding from an event.
The View which populated the Collection with an Item was no longer visible, but was still bound to a UI event which triggers the addition of an Item to the Collection. The sequence of events was approximately:
Event XYZ triggers creation of View2
View2 creates Item and adds to Collection.
( collection.length
now 1).
...Item removed from Collection.
( collection.length
now 0).
If Collection empty remove `View2`.
View2 removed.
At this point if Event XYZ is triggered again, two View2 instances will be created, therefore 2 items will be added to the collection . Even if an Item is removed from the Collection, the length is incremented by 1 each time the first Item is removed.
Summary: If you do $(myView).remove()
anywhere in your code and you have used events / binding, check you unbind from the event.