in backbone we have an app that uses an event Aggregator, located on the window.App.Events
now, in many views, we bind to that aggregator, and i manually wrote a destroy function on a view, which handles unbinding from that event aggregator and then removing the view. (instead of directly removing the view).
now, there were certain models where we needed this functionality as well, but i can't figure out how to tackle it.
certain models need to bind to certain events, but maybe i'm mistaken but if we delete a model from a collection it stays in memory due to these bindings to the event aggregator which are still in place.
there isn't really a remove function on a model, like a view has. so how would i tacke this?
EDIT on request, some code example.
App = {
Events: _.extend({}, Backbone.Events)
};
var User = Backbone.Model.extend({
initialize: function(){
_.bindAll(this, 'hide');
App.Events.bind('burglar-enters-the-building', this.hide);
},
hide: function(burglarName){
this.set({'isHidden': true});
console.warn("%s is hiding... because %s entered the house", this.get('name'), burglarName);
}
});
var Users = Backbone.Collection.extend({
model: User
});
var House = Backbone.Model.extend({
initialize: function(){
this.set({'inhabitants': new Users()});
},
evacuate: function(){
this.get('inhabitants').reset();
}
});
$(function(){
var myHouse = new House({});
myHouse.get('inhabitants').reset([{id: 1, name: 'John'}, {id: 1, name: 'Jane'}]);
console.log('currently living in the house: ', myHouse.get('inhabitants').toJSON());
App.Events.trigger('burglar-enters-the-building', 'burglar1');
myHouse.evacuate();
console.log('currently living in the house: ', myHouse.get('inhabitants').toJSON());
App.Events.trigger('burglar-enters-the-building', 'burglar2');
});
view this code in action on jsFiddle (output in the console): http://jsfiddle.net/saelfaer/szvFY/1/
as you can see, i don't bind to the events on the model, but to an event aggregator. unbinding events from the model itself, is not necessary because if it's removed nobody will ever trigger an event on it again. but the eventAggregator is always in place, for the ease of passing events through the entire app.
the code example shows, that even when they are removed from the collection, they don't live in the house anymore, but still execute the hide command when a burglar enters the house.
//The remove() method removes the 'player1' model from the collection. mycollection. remove([player1]);
BackboneJS allows developing of applications and the frontend in a much easier way by using JavaScript functions. BackboneJS provides various building blocks such as models, views, events, routers and collections for assembling the client side web applications.
Backbone. js is a model view controller (MVC) Web application framework that provides structure to JavaScript-heavy applications. This is done by supplying models with custom events and key-value binding, views using declarative event handling and collections with a rich application programming interface (API).
I see that even when the binding event direction is this way Object1 -> listening -> Object2 it has to be removed in order to Object1 lost any alive reference.
And seeing that listening to the Model remove
event is not a solution due it is not called in a Collection.reset()
call then we have two solutions:
As @dira sais here you can overwrite Collection._removeReference
to make a more proper cleaning of the method.
I don't like this solutions for two reasons:
super
after it.Collection.reset()
callsWich is the opposite: instead of adding deeper functionality, add upper functionality.
Then instead of calling Collection.reset()
directly you can call an implementation that cleanUp the models before been silently removed:
cleanUp: function( data ){
this.each( function( model ) { model.unlink(); } );
this.reset( data );
}
A sorter version of your code can looks like this:
AppEvents = {};
_.extend(AppEvents, Backbone.Events)
var User = Backbone.Model.extend({
initialize: function(){
AppEvents.on('my_event', this.listen, this);
},
listen: function(){
console.log("%s still listening...", this.get('name'));
},
unlink: function(){
AppEvents.off( null, null, this );
}
});
var Users = Backbone.Collection.extend({
model: User,
cleanUp: function( data ){
this.each( function( model ) { model.unlink(); } );
this.reset( data );
}
});
// testing
var users = new Users([{name: 'John'}]);
console.log('users.size: ', users.size()); // 1
AppEvents.trigger('my_event'); // John still listening...
users.cleanUp();
console.log('users.size: ', users.size()); // 0
AppEvents.trigger('my_event'); // (nothing)
Check the jsFiddle.
First thing we verify that Object1 listening to an event in Object2 creates a link in the direction Obect2 -> Object1:
In the above image we see as the Model (@314019) is not only retained by the users
collection but also for the AppEvents
object which is observing. Looks like the event linking for a programmer perspective is Object that listen -> to -> Object that is listened but in fact is completely the opposite: Object that is listened -> to -> Object that is listening.
Now if we use the Collection.reset()
to empty the Collection we see as the users
link has been removed but the AppEvents
link remains:
The users
link has disappear and also the link OurModel.collection
what I think is part of the Collection._removeReference()
job.
When we use our Collection.cleanUp()
method the object disappear from the memory, I can't make the Chrome.profile
tool to explicitly telling me the object @314019 has been removed but I can see that it is not anymore among the memory objects.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With