0
votes

I'm working on application that has several modules. Each module consists of one controller, modules/stores and a number of views which use these stores. So I decided to create main controller and one navigation view. When user changes the section of application the corresponding controller is loaded.

This is the source code of my main controller:

Ext.define('My.controller.Navigation', {
extend: 'Ext.app.Controller',
views: ['layout.Navbar'],
_loadedControllers: [],
init: function() {
    var me = this;
    me.control({
        'navbar > tabpanel': {
            tabchange: me.handleNavChange
        }
    });
},
handleNavChange: function(tabPanel, newCard, oldCard, eOpts) {
    var app = My.getApplication(),
        container = app.getContainerPanel(),
        components = Ext.ComponentQuery.query('viewport > panel > panel:not([cls~=bpte-layout])'),
        name = this.formatControllerName(newCard.itemId),
        i=0;
    //Remove initialized widgets:
    for(; i < components.length; i++) {
        container.remove( components[i], true );
    }
    //Load and initialize controller:
    controller = app.getController(name);
    if(this.isControllerLoaded(name))
        controller.init();
    this.addLoadedController(name);
},
formatControllerName: function(id) {
    return id.charAt(0).toUpperCase() + id.substr(1).toLowerCase();
},
isControllerLoaded: function(name) {
    for(var i=0; i < this._loadedControllers.length; i++) {
        if(this._loadedControllers[i] == name)
            return true;
    }
    return false;
},
addLoadedController: function(name) {
    this._loadedControllers.push(name);
}});

And this is the abstract source code of my controllers:

Ext.define('My.controller.ControllerX', {
    extend: 'Ext.app.Controller',
    stores: ['Store#1','Store#2'],
    views:  ['Widget#1','Widget#2','Widget#3'],
    init: function() {
        var container = My.getApplication().getContainerPanel();
        container.add( Ext.widget('Widget#1') );
        container.add( Ext.widget('Widget#2') );
        this.control({ ... });
        ...
    }
    ...
});

Everything works fine when I load child controllers for the first time. But when I navigate to the same child controller once again I have the problems with Stores. Stores act as like they are duplicated. For example when I add new model in the store and then sync the store, it adds two models instead of one and send them both to the server.

What am I doing wrong?

2
I didn't post the content of my child controllers in order not to overload you with unnecessary information. They work absolutely fine when loaded and initialized normally.Stas

2 Answers

0
votes

Controller.init should only ever be called once. Put a log inside your dynamically loaded controller init method, it's likely being called more than once.

0
votes

OK, I solved the problem for me. I have updated my main controller in the way it does not destroy views while removing, it stores them in corresponding variable and use these views when we navigate to the section that has been already loaded.

Ext.define('My.controller.Navigation', {
extend: 'Ext.app.Controller',
views: ['layout.Navbar'],
_loadedControllers: {},
init: function() {
    var me = this;
    me.control({
        'navbar > tabpanel': {
            tabchange: me.handleNavChange
        }
    });
},
handleNavChange: function(tabPanel, newCard, oldCard, eOpts) {
    var app = My.getApplication(),
        container = app.getContainerPanel(),
        components = Ext.ComponentQuery.query('viewport > panel > panel:not([cls~=bpte-layout])'),
        currentController = this.formatControllerName(oldCard.itemId),
        newController = this.formatControllerName(newCard.itemId),
        i=0;
    //Store old components and remove them from container:
    this._loadedControllers[currentController] = components;
    for(; i < components.length; i++) {
        container.remove( components[i], false );
    }
    if(this.isControllerLoaded(newController)) {
        //Restore widgets of already loaded controller:
        for(i=0; i < this._loadedControllers[newController].length; i++) {
            container.add(this._loadedControllers[newController][i]);
        }
    } else {
        //Load new controller:
        app.getController(newController);
    }
},
formatControllerName: function(id) {
    return id.charAt(0).toUpperCase() + id.substr(1).toLowerCase();
},
isControllerLoaded: function(name) {
    for(var key in this._loadedControllers) {
        if(!this._loadedControllers.hasOwnProperty(key))
            continue;
        if(key == name)
            return true;
    }
    return false;
}});

Furthermore the application became faster because widgets (views) are not rebuilt each time when we enter the section.