1. #1
    Sencha User
    Join Date
    Aug 2012
    Location
    Fabrègues, France
    Posts
    50
    Vote Rating
    0
    gostbuster is an unknown quantity at this point

      0  

    Default Destroy controller (Mitchell Simoens SubApp)

    Destroy controller (Mitchell Simoens SubApp)


    Hello,

    On a precedent topic ( http://www.sencha.com/forum/showthre...315&viewfull=1 ), I was looking for a way to load dynamically classes from Ajax Request.

    Browsing the forum, I found a very interesting project from Mitchell Simoens (you can find it here : https://github.com/mitchellsimoens/SubAppDemo ). Thank you Mitchell for sharing this.

    Well, I studied it the all day and got it almost work on my application, I modified the code from Mitchell to get it work on my app.

    Let me share this to you :

    SubApplication class (modified, initial code from Mitchell)

    Code:
    Ext.define('Ext.apm.SubApplication', { //apm is my name space, I put this file in /myapp/apm
        extend: 'Ext.app.Controller',
    
    
        requires: [
            'Ext.ModelManager',
            'Ext.data.Model',
            'Ext.data.StoreManager',
            'Ext.ComponentManager',
           // 'Ext.apm.EventBus' //forced to comment this to start...I'll speak of this later in the post
        ],
    
    
        /**
          * @cfg {Ext.app.Application} app Reference to the global Ext.app.Application instance
          */
        /**
          * @cfg {String} id ID of the SubApplication.
          */
    
    
        /**
          * @cfg {Array} controllers Array of Controller names to create.
          */
        /**
          * @cfg {Object} dependencies Object holding Arrays for CSS and JS files to load.
          * JS files will automatically be destroyed once all JS files are loaded.
          * CSS files will be automatically destroyed when SubApplication is destroyed
          */
        dependencies      : {
            css : [],
            js  : []
        },
        /**
          * @cfg {Boolean/Ext.LoadMask} loadMask true to use a Ext.LoadMask while loading dependencies.
          * Can also accept a config Object of Ext.LoadMask
          */
        loadMask          : true,
        /**
          * @cfg {String} loadingCls CSS name(s) to apply to the message div of Ext.LoadMask
          */
        loadingCls        : '',
        /**
          * @cfg {String} loadingText Text to show in the Ext.LoadMask
          */
        loadingText       : 'Loading...',
        /**
          * @cfg {Boolean} loadingUseMsg true to show a message in the Ext.LoadMask
          */
        loadingUseMsg     : true,
        /**
          * @cfg {Number}removeJSFileDelay Time in milliseconds to delay destroying JS files after all have been loaded
          */
        removeJSFileDelay : 100,
    
    
        scope             : undefined,
    
    
        /**
           * Function that will be called before the launch function but after all dependencies
           * have been loaded and Controllers created.
           * @property beforelaunch
           * @type Function
           */
        beforeLaunch : Ext.emptyFn,
         /**
           * Function that will be called after everything has been set up. Use this function
           * to create the SubApplication views.
           * NOTE: Return the main view as SubApplication will listen for it's destroy event to destroy the SubApplication.
           * @property launch
           * @type Function
           * @return {Ext.Component} Return the main view as SubApplication will listen for it's destroy event to destroy
           * the SubApplication.
           */
        launch       : Ext.emptyFn,
    
    
        constructor: function(config){
            config = config || {};
            var me          = this;
            var app         = config.app;
            
            var  controllers = Ext.Array.from(config.controllers);
    
    
    
    
        
            Ext.apply(config, {
                documentHead : Ext.getHead(),
                id           : config.id,
    
    
               // eventbus     : app.eventbus, //forced to comment
    
    
                //private
                //holds loaded JS files to remove after loading file
                loadedJS     : Ext.create('Ext.util.MixedCollection'),
                //private
                //holds loaded CSS files to remove on destruction
                loadedCSS    : Ext.create('Ext.util.MixedCollection'),
            });
    
    
            
            me.callParent(arguments);
            
            Ext.apply(me, {
                appControllers : controllers,
                controllers    : Ext.create('Ext.util.MixedCollection')
            });
            
            me.init();
           
        },
    
    
        init: function() {
            
            var me           = this,
                dependencies = me.config.dependencies, //needed to add config, cuz of ST 2 ?
                css          = dependencies.css,
                js           = dependencies.js,
                loadMask     = me.config.loadMask,
                cfg;
               
     /* pour le masque on verra apres  = I'll see later with that
                if (loadMask) {
                cfg = Ext.isObject(loadMask) ? loadMask : {
                        msg    : me.loadingText,
                        msgCls : me.loadingCls,
                        useMsg : me.loadingUseMsg
                    };
    
    
                me.loadMask = loadMask = Ext.create('Ext.LoadMask', Ext.getBody(), cfg);
                loadMask.show();
            }
            ***/
            Ext.each(css, function(file) {
               me.loadCSSFile(file);
            });
            
            Ext.each(js, function(file) {
                me.loadJSFile(file);
            });
            
           
           
              
        },
    
    
    
    
    
    
        
        loadCSSFile: function(file) {
            var me   = this,
                head = me.config.documentHead, //needed to add .config
                css  = document.createElement('link');
    
    
            Ext.apply(css, {
                href : file,
                rel  : 'stylesheet',
                type : 'text/css'
            });
    
    
            head.appendChild(css);
            me.loadedCSS.add(Ext.get(css));
        },
    
    
        //ajout de fichier js (par utile je pense, on va voir);
        loadJSFile: function(file) {
            var me     = this,
                head   = me.config.documentHead,
                script = document.createElement('script');
    
    
            Ext.apply(script, {
                src  : file,
                type : 'text/javascript',
                
                onload : Ext.Function.createDelayed(me.handleFileLoad, me.removeJSFileDelay, me, [script]),
                onreadystatechange : function() {
                    if (this.readyState === 'loaded' || this.readyState === 'complete') {
               
                        me.handleFileLoad(script);
                    }
                }
            });
    
    
            head.appendChild(script);
        },
    
    
        handleFileLoad: function(script) {
            script.onload = null;
            script.onreadystatechange = null;
            script.onerror = null;
    
    
            var me       = this,
                loadedJS = me.config.loadedJS;
    
    
            loadedJS.add(Ext.get(script));
            me.checkJSDependencyState();
        },
    
    
        checkJSDependencyState: function() {
            var me           = this,
                dependencies = me.config.dependencies,
                js           = dependencies.js,
                jsLen        = js.length,
                loadedJS     = me.config.loadedJS,
                loadedLen    = loadedJS.getCount();
    
    
            if (jsLen === loadedLen) {
                loadedJS.each(function(file) {
                    me.removeFile(file);
                    loadedJS.remove(file);
                });
    
    
                me.onBeforeLaunch();
            }
        },
    
    
        addController: function(controller, skipInit) {
          
            if (Ext.isDefined(controller.name)) {
                var name = controller.name;
                delete controller.name;
    
    
                controller.id = controller.id || name;
    
    
                controller = Ext.create(name, controller);
            }
    
    
            var me          = this,
                controllers = me.controllers;
            controllers.add(controller);
    
    
            if (!skipInit) {
                controller.init();
            }
    
    
            return controller;
        },
    
    
        removeController: function(controller, removeListeners) {
            removeListeners = removeListeners || true;
    
    
            var me          = this,
                controllers = me.controllers;
    
    
            controllers.remove(controller);
    
    
            if (removeListeners) {
                var bus = me.eventbus;
    
    
                bus.uncontrol([controller.id]);
            }
        },
    
    
    
    
        addSubApplication: function(subapp) {
            
            var me      = this,
                app     = me.config.app,
                subapps = app.subApplications;
    
    
            subapps.add(subapp);
    
    
            return subapp;
        },
    
    
        removeSubApplication: function(subapp) {
            var me      = this,
                app     = me.config.app, //config needed
                subapps = app.subApplications;
    
    
            subapps.remove(subapp);
        },
    
    
        removeFile: function(file) {
            console.log('zermove file');
            Ext.destroy(file);
        },
    
    
        onBeforeLaunch: function() {
            
            var me          = this,
                app         = me.config.app,
                controllers = me.appControllers,
                loadMask    = me.config.loadMask,
                controller, subapp;
               
            if (app) {
                Ext.each(controllers, function(controlName) {
                    controller = {
                        application : app,
                        name        : controlName
                    };
                    controller = me.addController(controller);
                });
    
    
                delete me.appControllers;
    
    
                Ext.applyIf(app, {
                    subApplications : Ext.create('Ext.util.MixedCollection')
                });
    
    
                subapp = me.addSubApplication(me);
            }
            me.beforeLaunch.call(me.scope || me);
    
    
            /**on cache le mask 
            if (loadMask) {
                loadMask.hide();
            }
            */
            
        var cmp =me.config.launch();//this line work
          //  var cmp = me.launch.call(me.scope || me);//this line doesn't work
    
    
            if (cmp) {
                me.cmp = cmp;
                cmp.on('destroy', me.handleSubAppDestroy, me);
            }
        },
    
    
        handleSubAppDestroy: function(cmp) {
            var me             = this,
                app            = me.app,
                bus            = app.eventbus,
                appControllers = app.controllers,
                controllers    = me.controllers,
                cssFiles       = me.loadedCSS,
                deleteThis     = false,
                appController, idx;
    
    
            controllers.each(function(controller) {
                me.removeController(controller);
            });
    
    
            cssFiles.each(function(file) {
                me.removeFile(file);
    
    
                cssFiles.remove(file);
            });
    
    
            me.removeSubApplication(me);
    
    
            me.loadedCSS = null;
            me.loadedJS  = null;
            me = null;
        }
    });
    and here is how I use this class:

    Code:
                                                         var me     = this,
                                    app    = me.getApplication(),//changed for ST2
                                  
                                        subapp = Ext.create('Ext.apm.SubApplication',{
                                        application : app, //otherwise you get a getRouter of undefined error...
                                        app          : app,
                                        id           : 'MyWidget.controller.View',
                                        loadMask     : true,
                                        loadingText  : 'Loading Test...',
                        
                                        controllers : [
                                            'MyWidget.controller.Controller'
                                        ],
                        
                                        dependencies : {
                                            css : [
                                                'http://myserver/mywidget/mycss.css'
                                            ],
                                            js  : [
                               'http://myserver/mywidget/mycode.js',//contains all the widget code
                                            ]
                                        },
                        
                                        launch: function() {
                                            
                                            var widgetPanel = Ext.create('AirformSuivi.view.Formmonitor', {
                                                app : me
                                            });
                                           
                                            me.getPortal().add(widgetPanel); //portal is the panel
                                            
                                            me.getPortal().setActiveItem(1);//with a layout card
                                        }
                                    });

    Well no problem with that, that works ! I able to get code from server side, and I can instanciate the controller (=> events ok, etc...)

    The issue is when removing Controller : the class EventBus doesn't exist in Sencha Touch 2 (that's why I commented it). Now I don't see how I can easily destroy the controller,

    Any Ideas (Mitchell ?)

    Thank you very much in advance

  2. #2
    Sencha - Senior Forum Manager mitchellsimoens's Avatar
    Join Date
    Mar 2007
    Location
    Gainesville, FL
    Posts
    37,330
    Vote Rating
    847
    mitchellsimoens has a reputation beyond repute mitchellsimoens has a reputation beyond repute mitchellsimoens has a reputation beyond repute mitchellsimoens has a reputation beyond repute mitchellsimoens has a reputation beyond repute mitchellsimoens has a reputation beyond repute mitchellsimoens has a reputation beyond repute mitchellsimoens has a reputation beyond repute mitchellsimoens has a reputation beyond repute mitchellsimoens has a reputation beyond repute mitchellsimoens has a reputation beyond repute

      0  

    Default


    The reason it needs the EventBus is so that it can remove the listeners from the this.control call. In Sencha Touch 2, you need to remove the listeners from the event dispatcher on the Ext.app.Application. Check out the control method of Ext.app.Application to see how to remove it, looks pretty easy.
    Mitchell Simoens @SenchaMitch
    Sencha Inc, Senior Forum Manager
    ________________
    Check out my GitHub, lots of nice things for Ext JS 4 and Sencha Touch 2
    https://github.com/mitchellsimoens

    Think my support is good? Get more personalized support via a support subscription. https://www.sencha.com/store/

    Need more help with your app? Hire Sencha Services services@sencha.com

    Want to learn Sencha Touch 2? Check out Sencha Touch in Action that is in print!

    When posting code, please use BBCode's CODE tags.

  3. #3
    Sencha User
    Join Date
    Aug 2012
    Location
    Fabrègues, France
    Posts
    50
    Vote Rating
    0
    gostbuster is an unknown quantity at this point

      0  

    Default


    Thank you Mitchell you're great !
    I'm gonna look for what you said !
    I'll give you news, thanks,

  4. #4
    Ext JS Premium Member
    Join Date
    Sep 2007
    Posts
    55
    Vote Rating
    0
    mvarshavsky is on a distinguished road

      0  

    Default


    So, something along the lines of (let's say in pseudo code)?
    HTML Code:
    Ext.define('MY-Ext.app.Application',
        override:   'Ext.app.Application'
        uncontrol:  (controller) ->
            dispatcher = @getEventDispatcher()
            #for each selector string
            _.each(@getEventDispatcher().listenerStacks?.component, (target) ->
                #listener stack corresponding to each map
                _.each(target, (stack) ->
                    #find and remove listeners scoped to our controller
                    _.each(stack.getAll(), (listener) ->
                        if listener.scope == controller
                            stack.remove(listener.fn, listener.scope)
                    )
                )
            )
    )

  5. #5
    Sencha User
    Join Date
    Aug 2012
    Location
    Fabrègues, France
    Posts
    50
    Vote Rating
    0
    gostbuster is an unknown quantity at this point

      0  

    Default


    Hi,
    Did you find a solution, I tried some code, but the solution is not found...

    Let me share this :
    In the subapplication class, I rewrited the methode 'removeController'

    Code:
     removeController: function(controller, removeListeners) {
            removeListeners = removeListeners || true;
            var me          = this,
                controllers = me.controllers;
    
    
          
            var dispatcher = MyApp.app.getEventDispatcher();
    
    
     Ext.each(dispatcher.listenerStacks.component, function(target,index) {
     //forced to use for loop to browse the object
      for (var key in target) {
              if (target.hasOwnProperty(key)) {
              var mytarget = target[key];
                 for (var key2 in mytarget) {
                  if (mytarget.hasOwnProperty(key2)) {
                   var event = mytarget[key2];
                    Ext.each(event.listeners, function(listener,index) {
                    //the listener.scope doesn't exists !
                      console.log(listener.scope);
                      });
                               }
                               }
                                
                            }
                   }
                
            });
           
    
    
        },
    Actually I didn't found à scope parameter in listener object.
    Some more help would be great.
    Thank you in advance.

  6. #6
    Sencha User
    Join Date
    Aug 2012
    Location
    Fabrègues, France
    Posts
    50
    Vote Rating
    0
    gostbuster is an unknown quantity at this point

      0  

    Default


    Futhermore, I didn't find any control method for the Ext.app.Application class (neither observable, controller, etC...)

  7. #7
    Ext JS Premium Member
    Join Date
    Sep 2007
    Posts
    55
    Vote Rating
    0
    mvarshavsky is on a distinguished road

      0  

    Default


    scope will be part of what's in Ext.event.ListenerStack

  8. #8
    Sencha User
    Join Date
    Aug 2012
    Location
    Fabrègues, France
    Posts
    50
    Vote Rating
    0
    gostbuster is an unknown quantity at this point

      0  

    Default


    Hello, I worked again with this and advanced... Here is the code which works, except that it 'kills' all the events and not only the designated controller events :

    Code:
    removeController: function(controller, removeListeners) {
            
            removeListeners = removeListeners || true;
    
    
            var me          = this,
                controllers = me.controllers;
            var dispatcher =Myapp.app.getEventDispatcher();
       Ext.each(dispatcher.listenerStacks.component, function(target,index) {
           
     for (var key in target) {
          if (target.hasOwnProperty(key)) {
            var stack = target[key];
             for (var key2 in stack) {
             if (stack.hasOwnProperty(key2)) {
             var listener = stack[key2];
              var listeners=listener.getAll();
              for(var i=0;i<listeners.length;i++)
               {
                var scope=listeners[i].scope;
                 var fn=listeners[i].fn;
                 listener.remove(fn, scope)
                   }
            }
             }
                          }
                          }
        
            });
        },
    I'm now trying to remove only my subapp controller event....

    Any clue is welcome
    Thank you very much in advance

  9. #9
    Sencha User
    Join Date
    Aug 2012
    Location
    Fabrègues, France
    Posts
    50
    Vote Rating
    0
    gostbuster is an unknown quantity at this point

      0  

    Default


    Well, actually there is something I don't understand, this is a thing that mvarshavsky suggested :

    HTML Code:
        if listener.scope == controller 
     stack.remove(listener.fn, listener.scope)
    I translated it in my function :

    Code:
    removeController: function(controller) {
      var me          = this,
      controllers = me.controllers;
        var dispatcher = MyApp.app.getEventDispatcher();
    
    
        Ext.each(dispatcher.listenerStacks.component, function(target,index) {
        for (var key in target) {
        if (target.hasOwnProperty(key)) {
       var stack = target[key];
       for (var key2 in stack) {
         if (stack.hasOwnProperty(key2)) {
         var listener = stack[key2];
        var listeners=listener.getAll();
        for(var i=0;i<listeners.length;i++)
                      {
               var scope=listeners[i].scope;
              var fn=listeners[i].fn;
                        This is never equal !
    
       if(controllers==scope)
                {
               listener.remove(fn, scope)
                  }
            }
            }
            }
                          }
                          }
        
            });
           
            
          
          
        }


    I don't know how scope could be equal to controllers to remove..... I analysed the objects and this is not the same at all.... what am I missing ??