0

I'm having troubles handling events between my views and collections. In the below example you can find a short version of what does my webapp look like and how are the events being handled now.

What happens here is that when switching from menu1 to menu2 or even when going backwards, it causes that the "APP:change_city" event listener is stacked up. So when I then trigger this event , it calls the method OnCityChange() as many times as I switched between the menus.

I'm now not really sure whether I'm using the event aggregator (eMgr) correctly. Can anyone please assist?

eMgr.js

define(['backbone.wreqr'],function(Wreqr){
    "use strict";
    return new Wreqr.EventAggregator();
})

AppRouter.js

define(['marionette'],  function (Marionette) {
    "use strict";

    var AppRouter = Marionette.AppRouter.extend({
        appRoutes: {
            'menu1' : 'showMenu1',
            'menu1' : 'showMenu2'
        }
    });

    return AppRouter;
});

AppControler.js

define(['underscore', 'backbone', 'marionette', '../eMgr'],  function (_, Backbone, Marionette, eMgr) {
    "use strict";

    var Controller = Marionette.Controller.extend({
            initialize: function(){
                console.log("AppRouter - Init")
            },

            showMenu1: function (city) {
                console.log(" [Info] [AppControler] opening Menu1");
                eMgr.trigger("APP:open_menu", { menu: "Menu1", city: city});
            },

            showMenu2: function (city) {
                console.log(" [Info] [AppControler] opening Menu2");
                eMgr.trigger("APP:open_menu", { menu: "Menu2", city: city});
            }
    });

    return Controller;
});

App.js

define([ 'backbone', 'underscore', 'marionette', 'eMgr',  
    'layouts/MainMenu/layoutview.menu1',
    'layouts/MainMenu/layoutview.menu2',
    'controllers/AppController', 'routers/AppRouter'], 
    function (Backbone, _, Marionette,  eMgr,  
    lv_mainmenu1, lv_mainmenu2,
    AppController, AppRouter) {
    "use strict";

    var MyApp = new Marionette.Application();
    var controller = new AppController();

    MyApp.addRegions({
        .....
        mainmenu: '#main_menu',
        .....
    });

    MyApp.listenTo(eMgr, "menu_changed",function(eData){
        switch(eData.menu){
            case "Menu1":
                MyApp.mainmenu.show(new lv_mainmenu1(eData));
                break;
            case "Menu2": 
                MyApp.mainmenu.show(new lv_mainmenu2(eData));
                break;
        }
    });

    MyApp.addInitializer(function(options) {
        var router = new AppRouter({
          controller : controller
        });
    });


    MyApp.on("start", function(){
      if (Backbone.history){
          Backbone.history.start();
      }
    });

    $(document).ready(function() {
        MyApp.start();
    });
});

layoutview.menu1.js

define([ 'backbone', 'underscore', 'marionette', 
            'templates/template.mainmenu', 
            'layouts/MainMenu/collectionview.categories'],
    function (Backbone, _, Marionette, t_Menus, c_Categories, cv_Categories) {
    "use strict";
    var Menu1LayoutView = Marionette.LayoutView.extend({

        template: t_Menus['menu1'],

        regions: {
            menu : '#menu'
        },

        initialize: function(options){
            this.city = options.city
        },


        onRender: function(){
        },

        onShow: function(){
            this.menu.show(new cv_Categories({city:this.city}));
        }
    });

    return Menu1LayoutView;
});

collectionview.categories.js

define([ 'backbone', 'underscore', 'marionette',
    'layouts/MainMenu/compositeview.subcategories',
    'collections/MainMenu/MM.collection.categories'], 
    function (Backbone, _, Marionette, cv_Subcategories, c_Categories) {
    "use strict";
    var CategoriesCollectionView = Marionette.CollectionView.extend({

        initialize: function(options){
            this.collection = new c_Categories([], {city: options.city});
        },

        getChildView: function(model){
            return cv_Subcategories;
        },

        onRender: function(){
        },
         onShow: function(){
        }
    });

    return CategoriesCollectionView;
});

This is where all the categorie's data are fetched from , it also re-fetches the data once the APP:change_city event is being triggered.

MM.collection.categories.js

    define([ 'underscore',  'backbone', 'eMgr','models/MainMenu/MM.model.category'], function(_, Backbone, eMgr, m_Category){
  var CategoriesCollection = Backbone.Collection.extend({
    model: m_Category,

    initialize: function(attr, opts) {
        this.city = opts.city;
        this.fetch();
        eMgr.once("APP:change_city", this.OnCityChange, this)
    },

    url: function(){
        return 'AF_GetCategories?city='+this.city;
    },

    OnCityChange: function(eData){
        /// this is the part which is being called multiple times !!!!!   ////
        /// when checking eMgr's events , it shows that the events are stacking up .. 
        this.url= 'AF_GetCategories?city='+eData.city;
        this.fetch();
    }
  });

  return CategoriesCollection;
});

compositeview.subcategories.js

define([ 'backbone', 'underscore', 'marionette',
    'templates/template.mainmenu', 
    'layouts/MainMenu/itemview.subcategory'], 
    function (Backbone, _, Marionette, t_MainMenu, iv_Subcategory) {
    "use strict";
    var SubcategoriesCompositeView = Marionette.CompositeView.extend({

        template: t_Menus['subcategorieslayout'],

        childViewContainer: "#category-wrapper",

        getChildView: function(model){
            return iv_Subcategory;
        },

        initialize: function(){
            this.collection = this.model.get("subcategories");
        },


        onRender: function(){
        },

        onShow: function(){
            this.$el.find("#loading").fadeOut(150);
        }
    });

    return SubcategoriesCompositeView;
});
Wracker
  • 589
  • 10
  • 32
Alexus
  • 1,887
  • 1
  • 23
  • 50

1 Answers1

0

I have come to a conclusion that keeping the event listeners this.listenTo("custom_event", this.do_something) in either model or collection isn't a good idea. The events weren't cleaned up properly while switching between menu1 and menu2. It only worked when I manually called eMgr.stopListening() before loading any views.

So I tried moving all the event listeners from models/collections to their views and Voila!...it all worked! Events are no longer being triggered multiple times as before.

Alexus
  • 1,887
  • 1
  • 23
  • 50