Looks like we can't reproduce the issue or there's a problem in the test case provided.
  1. #1
    Sencha User steffenbrem's Avatar
    Join Date
    Mar 2012
    Posts
    36
    Vote Rating
    2
    steffenbrem is on a distinguished road

      1  

    Default getController() events called multiple times (Eventbus problem) BUG

    getController() events called multiple times (Eventbus problem) BUG


    FIX
    Code:
    Ext.override(Ext.app.Controller,{
        control: function() {
            if ( ! this.blockControl ) {
                this.blockControl = true;
                this.callParent(arguments);
            }
        }
    });
    Hello guys,

    I found a bug when using getController() to get a controller instance and setting event's in the control() method of a controller. When a controller is called for the first time (this.getController('controller1')), everything is fine, but when it's called again it fires all event's twice. If you then call it again, all event's are called three times!

    I think this is a serious bug, maybe I am doing something wrong, so I will post a sample code:

    Application:
    Code:
    Ext.application({
        name: 'Radiaal',
        appFolder: Ext.baseUrl + 'assets/js/radiaal-app/app',
        
        controllers: ['Main'],
        
        launch: function() {
            Ext.create('Radiaal.view.Viewport', {
                renderTo: 'extjs_app_wrapper'
            });
        }
    });
    Main controller:
    Code:
    Ext.define('Radiaal.controller.Main', {
        extend: 'Ext.app.Controller',
        
        onLaunch: function() {
            var self = this;
                    
            // URL Routing and mapping                
            G.Path.route('gebruikers', 'users');
            G.Path.route('klanten', 'customers');
                    
            G.Path.root('#/dashboard');
            
            // This URL listener, listens for hash changes in the URL. It will dispatch it and convert it into
            // "controller/action/params" format.
            G.Path.listen(function(controller, action, params) {
                controller = controller.capitalize();
    
    
                var exists = OSP.Radiaal.fileExists('assets/js/radiaal-app/app/controller/' + controller + '.js');
                        
                 if ( exists ) {
                     var controllerObj = self.getController(controller);                 
                     
                     if ( ! action ) {
                         return controllerObj.index();
                     } else if ( typeof controllerObj[action] === 'function' ) {
                         return controllerObj[action].apply(controllerObj, params);
                     }
                 }
                        
                 self.getController('NotFound').index();
            });
        }
    });
    Customers Controller:
    Code:
    Ext.define('Radiaal.controller.Customers', {
        extend: 'Ext.app.Controller',
        
        views: [
            'customers.Index',
        ]
    
    
        index: function() {
            // Changes the actual page to the new view
            OSP.Radiaal.setPage('customersindex');
            
            // Event's setup
            this.control({
                'customersindex button[action=create]': {
                   click: function(button) {
                        // This is a custom Window that will me shown when the user clicks the button.
                        var w = Ext.create('Radiaal.view.customers.index.CreateCustomer');
                        w.show();
                    }
                },
    Now, when we have a URL like this: http://localhost/extjs/#/customers it will call the Customers controller. If you then, navigate to any other URL (say: http://localhost/extjs/#/user) and then switch back to http://localhost/extjs/#/customers ALL event's within this.control() are called twice (because getController('Customers') is called for the second time)! I hope I'm doing something wrong here, I've searched the forums but didn't find any solution yet.

    Thanks!


    Steffen

  2. #2
    Sencha - Ext JS Dev Team evant's Avatar
    Join Date
    Apr 2007
    Location
    Sydney, Australia
    Posts
    16,657
    Vote Rating
    584
    evant has a reputation beyond repute evant has a reputation beyond repute evant has a reputation beyond repute evant has a reputation beyond repute evant has a reputation beyond repute evant has a reputation beyond repute evant has a reputation beyond repute evant has a reputation beyond repute evant has a reputation beyond repute evant has a reputation beyond repute evant has a reputation beyond repute

      0  

    Default


    There's not really enough information. First off, what Ext version are you using?

    Secondly, what is the "G" object in your application? When does it make a call to getController? Please put together a test case without any external dependencies.

    Also, not really convinced the bug is on our side. If you look at /examples/app/simple and change the users controller:

    Code:
    Ext.define('AM.controller.Users', {
        extend: 'Ext.app.Controller',
    
        stores: ['Users'],
    
        models: ['User'],
    
        views: ['user.Edit', 'user.List'],
    
        refs: [
            {
                ref: 'usersPanel',
                selector: 'panel'
            }
        ],
    
        init: function() {
            console.log('init fired');
            this.control({
                'viewport > userlist dataview': {
                    itemdblclick: this.editUser
                },
                'useredit button[action=save]': {
                    click: this.updateUser
                }
            });
        },
    
        editUser: function(grid, record) {
            console.log('Getting controller');
            this.getController('Users');
        },
    
        updateUser: function(button) {
        }
    });
    You'll see init is only fired once no matter how many times you get the user controller.
    Evan Trimboli
    Sencha Developer
    Twitter - @evantrimboli
    Don't be afraid of the source code!

  3. #3
    Sencha User steffenbrem's Avatar
    Join Date
    Mar 2012
    Posts
    36
    Vote Rating
    2
    steffenbrem is on a distinguished road

      0  

    Default


    I'm using Ext JS 4.1.1 and the G.Path object is a Javascript library to dispatch the hash in the URL. It works very nice with Ext JS.

    Hmm, I think that the problem is that I setup the listeners in the index() method. This method is called every time you will call controller/index. The controller will then have those events doubled.

    Is there any way to prevent this? I mean, I setup the view in the method, but also the listeners, is there some trick that those listeners won't be appended? I can't leave the call to index() away.

    I will try some stuff, if I got a good solution I will post it here.

    Thanks!

  4. #4
    Sencha - Ext JS Dev Team evant's Avatar
    Join Date
    Apr 2007
    Location
    Sydney, Australia
    Posts
    16,657
    Vote Rating
    584
    evant has a reputation beyond repute evant has a reputation beyond repute evant has a reputation beyond repute evant has a reputation beyond repute evant has a reputation beyond repute evant has a reputation beyond repute evant has a reputation beyond repute evant has a reputation beyond repute evant has a reputation beyond repute evant has a reputation beyond repute evant has a reputation beyond repute

      0  

    Default


    Why not just set a flag on the controller?
    Evan Trimboli
    Sencha Developer
    Twitter - @evantrimboli
    Don't be afraid of the source code!

  5. #5
    Sencha User steffenbrem's Avatar
    Join Date
    Mar 2012
    Posts
    36
    Vote Rating
    2
    steffenbrem is on a distinguished road

      0  

    Default


    I could do that, but it's a very big application. So to set those flags every time is not really efficient. Maybe I could override the Ext.app.Controller and check there if control settings already has been set? If so, then skip the current control() action.

    I will look into this, thanks evant!

  6. #6
    Sencha User mberrie's Avatar
    Join Date
    Feb 2011
    Location
    Bangkok, Thailand
    Posts
    506
    Vote Rating
    14
    mberrie will become famous soon enough mberrie will become famous soon enough

      0  

    Default


    steffen,

    I think you have a design flaw in the way that your index() method registers event listeners (via control()) each time it is triggered. getController() will return the cached instance once the controller has been created, but your index() method will register new listeners each time it is called.

    Standard Ext design pattern is that you register events in the controller's init() method. It should also be noted that Ext currently has no strategy in place to unregister events when a controller is destroyed. Controllers are meant to be created once (on application startup) and exist during the entire lifecycle of the application.

    Of course in larger applications this is most likely not gonna work. See the forum discussion on 'big applications', 'sub applications' and 'mvc'.

    In our current application we don't register controllers with the application but create and destroy them ourselves (make sure you call init() after instantiating a controller, or use getController() alternatively). When you destroy a controller you need to unregister its listeners. See this thread for how to implement an 'uncontrol' method.

    Of course you can also register listeners in index(), anyway, you will have to take care of cleaning them up properly once you navigate away from 'index'.

    Also, a simple boolean flag on the controller, like evant suggested, e.g. this.indexEventsRegistered=true could take care to avoid registering listeners multiple times (since getController will always return the same controller instance).
    However, at some point you should probably destroy the controller and clean up the listeners anyway.

  7. #7
    Sencha Premium Member gary.bake's Avatar
    Join Date
    May 2013
    Location
    Manchester UK
    Posts
    9
    Vote Rating
    1
    gary.bake is on a distinguished road

      1  

    Default getApplication().getController()

    getApplication().getController()


    Hi,


    I had the same problem in our application (using ExtJs 4.2.1) which I traced down to additional controllers being created when calling .getApplication().getController() methods


    We define the controller as below
    Code:
    Ext.define('CPA.controller.ResourceDetailControl', {
        extend: 'Ext.app.Controller',
        alias: 'widget.ResourceDetailControl',
        init....
        aMethod.....

    In another part of the application we had
    Code:
    CPA.getApplication().getController('CPA.controller.ResourceDetailControl').aMethod

    I found that calling this caused another instance of the controller to be created and hence another set of listeners attached to the controls.
    Changing the call to the below fixed the problem
    Code:
    CPA.getApplication().getController('ResourceDetailControl').aMethod
    I had a quick look at the source code and it looks like its not finding the full class name and then creating it.