3
votes

I am having an issue in my Backbone Marionette application where my child views are not being destroyed completely. How do you properly destroy a nested layout view that you are replacing with another layout/item view?

I was under the impression from the Marionette documentation on destroying layout views, that when I set a region to display a new view, that the old view is destroyed. However, events that are triggered via vent are still visible by the old view that was supposedly destroyed.

I created a sample of this issue here: https://jsfiddle.net/dhardin/5j3x2unx/

I believe the issue stems from my router:

App.Router = Marionette.AppRouter.extend({
  routes: {
    '': 'showView1',
    'view1': 'showView1',
    'view2': 'showView2'

  },
  showView1: function() {
    var view1 = new App.View1();
    App.Layout.mainRegion.empty();
    App.Layout.mainRegion.show(view1);
  },
  showView2: function() {
    var view2 = new App.View2();
    App.Layout.mainRegion.empty();
    App.Layout.mainRegion.show(view2);
  }
});

The App.Layout.mainRegion.empty() is not required to my understanding as that is taken care of when the view is destroyed in the Region Manager's show() function. To see the issue, navigate to another view via navigation, and click the button. You will see that the alert is fired for both the old view and the new view.

Back in my pre-marionette applications, I followed a clean-up pattern to avoid these memory leaks discussed here.

Essentially, my displayed view would call the following function when my app changes to a new view:

Backbone.View.prototype.close = function(){
  this.remove();
  this.unbind();
}

Please let me know if you need any additional info. Thanks in advance!

2

2 Answers

1
votes

For cases such as this you should take advantage of the onDestroy function to do additional clean-up work beyond what Marionette provides. Marionette automatically calls onDestroy when a view is replaced or removed.

onDestroy: function() {
     App.vent.off('ButtonClicked', this.onButtonClicked, this);
  }

From the Marionette documentation:

By providing an onDestroy method in your view definition, you can run custom code for your view that is fired after your view has been destroyed and cleaned up. The onDestroy method will be passed any arguments that destroy was invoked with. This lets you handle any additional clean up code without having to override the destroy method.

See the working fiddle here: https://jsfiddle.net/ocfn574a/

Note that I did update a typo in your routes config: 'showVeiw1' -> 'showView1'

1
votes

You should be using this.listenTo(App.vent, 'ButtonClicked', this.onButtonClicked) instead of App.vent.on('ButtonClicked', this.onButtonClicked, this); this way marionette takes care to take off all the listeners when the view is destroyed and you do not need to explicitly handle onDestory event to take off the listener. see the updated fiddle here. So basically there is no issue in your router but there is issue in registering the listener since the listener is not present in the view object it is not getting unregistered.