This time I’m struggling with the different methods to bind events. I’ve all the mentioned methods in my code. I just don’t know, if I’m on the right way. Maybe I should always use bindTo to ensure that my views are closed completely after a change (at present this would often yield errors)? Are there any best practices which will help me to get in the right direction?
To illustrate my current understanding of Marionette, here’s one module from my app. As always, every hint is very welcome.
PP.module('Grid', function(Grid, PP, Backbone, Marionette, $, _){
Grid.Product = Backbone.Model.extend({});
Grid.ProductCollection = Backbone.Collection.extend({
model: Grid.Product,
url: '/products/query'
});
Grid.ProductView = Backbone.Marionette.ItemView.extend({
className: 'grid',
template: 'public/templates/grid-template'
});
// Helper Methods
// -----------------------
var getGenderCode = function(genderName){
var genderMap = {
'men': 'M',
'women': 'W',
'unisex': 'A'
}
return genderMap.genderName;
}
// Public API
// -------------------
Grid.renderGrid = function(productCollection){
Grid.productView = new Grid.ProductView({
collection: productCollection
});
Grid.productView.bind('show', function(){
$('#isotope-container').isotope({
itemSelector : '.item',
containerStyle: {
position: 'relative',
zIndex: 1
}
});
});
PP.Layout.mainRegion.show(Grid.productView);
}
// Event Handlers
// -----------------------
PP.vent.bind('grid:requested', function(categoryData){
// use bootstrapped data on first start
if (PP.App.bootstrappedCategoryName !== categoryData.categoryName) {
Grid.productCollection.fetch({
data: {
gender: getGenderCode(categoryData.categoryName),
category: categoryData.categoryId
}
});
}
else {
PP.vent.trigger('mainview:ready', {
categoryName: PP.App.bootstrappedCategoryName
});
}
});
// Initializer
// --------------------
PP.addInitializer(function(options){
Grid.productCollection = new Grid.ProductCollection();
Grid.productCollection.on('reset', function(){
Grid.renderGrid(Grid.productCollection);
});
Grid.productCollection.reset(options.newArrivalsList);
});
});
the general guidelines is that any time you have an object that is created and destroyed throughout the life of the application, and that object needs to bind to events from some other object, you should use the
EventBinder.Views And Memory Leaks
Views are the perfect example of this. Views get created and destroyed all the time. They also bind to a lot of different events from both the
modelandcollectionon the view. When the view is destroyed, those events need to be cleaned up. By using the built-inbindTomethod on the view, the event handlers will be cleaned up for you. If you don’t usebindToand instead useondirectly, you’ll have to manually calloffto unbind the events when the view is closed / destroyed. If you don’t, you’ll end up with zombies (memory leaks).If you haven’t read them yet, check out these articles:
http://lostechies.com/derickbailey/2011/09/15/zombies-run-managing-page-transitions-in-backbone-apps/
http://lostechies.com/derickbailey/2012/03/19/backbone-js-and-javascript-garbage-collection/
Custom Event Groupings
Views are not the only place that this applies, though, and not the only use case for
EventBinder.If you are working with handful of objects, binding to their events, and those objects can be replaced with other object instances, then an
EventBinderwould be useful. In this case, think of the EventBinder as a collection or group of events for related objects.Let’s say you have ObjA, ObjB and ObjC. Each of these fires some events, and you want to make sure you clean up the event handlers when your code is done. This is easy with an
EventBinder:Calling
stopin this code will properly clean up all the event handlers for this use.When To Use
on/offDirectlyThe converse to all of this, is to say that you don’t always need to use an
EventBinder. You can get away without it, always. But you need to remember to clean up your events when necessary.In situations that do not need event handlers to be cleaned up, there is no need to use an
EventBinder, as well. This may be an event that a router triggers, or that theMarionette.Applicationobject triggers. For those application lifecycle events, or events that need to live throughout the entire life of the app, don’t bother with anEventBinder. Instead, just let the event handlers live on. When the person refreshes the browser window, or navigates to a different site, the handlers will be cleaned up at that point.But when you need to manage your memory and event handlers, cleaning up references and closing things down without refreshing the page or navigating away from it, then
EventBinderbecomes important as it simplifies event management.