8

Let's say I have a main controller, then my application has a controller for each "module". This main controller contains the viewport, then a header (with a menu) + a "centered" container, which is empty at the beginning.

A click in the menu will change the current module/controller and the adhoc view (which belongs to this controller) will be displayed in the centered container.

I think it's a very simple scenario, but strangely I didn't find the proper way to do it. Any ideas? Thanks a lot!

TigrouMeow
  • 1,038
  • 4
  • 19
  • 30

2 Answers2

9

Here is what I do: I have a toolbar on top, a left navigation and the center location is work area (basically a tab panel) like you mentioned. Lets take each part fo the application and explain.First, here is how my viewport look like:

Ext.define('App.view.Viewport',{
    extend: 'Ext.container.Viewport', 
    layout: 'border',
    requires: [
        'App.view.menu.NavigationPane',
        'App.view.CenterPane',          
        'App.view.menu.Toolbar'
    ], 
    initComponent: function() {
        Ext.apply(this, {
            items: [{
                region: 'north',
                xtype: 'panel',                 
                height: 24,                                     
                tbar: Ext.create('App.view.menu.Toolbar')                                       
            },{
                title: 'Navigation Pane',
                region: 'west',
                width: 200,
                layout: 'fit',
                collapsible: true, 
                collapsed: true,
                items: Ext.create('App.view.menu.NavigationPane')                                       
            },{
                region: 'center',                                               
                xtype: 'centerpane'                                     
            }]       
         });

        this.callParent(arguments);
     }
});

You can see that I have a toolbar (App.view.menu.Toolbar) with menu and left navigation (App.view.menu.NavigationPane). These two, components make up my main menu or gateway to other modules. Users select the menu item and appropriate module views (like form, grid, charts etc) get loaded into the 'centerpane'. The centerpane is nothing but a derived class of Ext.tab.Panel.

Like you said, I have a main controller that handles all the requests from the toolbar and navigation pane. It handled only the toolbar and navigation pane's click actions. Here is my AppController:

Ext.define('CRM.controller.AppController',{
    extend: 'Ext.app.Controller',    
    init: function() {

        this.control({   

            'apptoolbar button[action="actionA"]' : {
                     click : function(butt,evt) {
                             this.application.getController('Controller1').displayList();
                     }
             },  
             .
             .  // Add all your toolbar actions & navigation pane's actions...
             .           
             'apptoolbar button[action="actionB"]' : {
                     click : function(butt,evt) {
                            this.application.getController('Controller2').NewRequest(); 
                     }
             }
        });     
     } 
 });

Look at one of my button's handler. I get hold of the controller through the 'application' property:

this.application.getController('Controller2').NewRequest(); 

With the help of getController method, I get the instance of the controller and then call any method inside my controller. Now lets have a look at the skeleton of my module's controller:

Ext.define('CRM.controller.Controller2',{
    extend: 'Ext.app.Controller',    
    refs: [         
        {ref:'cp',selector: 'centerpane'}, // reference to the center pane
        // other references for the controller
    ],
    views: ['c2.CreateForm','c2.EditForm','c2.SearchForm','c2.SearchForm'],
    init: function() {

        this.control({   

            'newform button[action="save"]' : {
                // Do save action for new item
            },  
            'editform button[action="save"]' : {
                // update the record...
            },  
            'c2gridx click' : {
                // oh! an item was click in grid view
             }
        });     
    },
    NewRequest: function() {
        var view = Ext.widget('newform');
        var cp = this.getCp();      // Get hold of the center pane... 
        cp.add(view);   
        cp.setActiveTab(view);
    },
    displayList: function() {
        // Create grid view and display...
    }   
 });

My module's controller have only the actions related to that module (a module's grid, forms etc). This should help you get started with rolling in right direction.

Abdel Raoof Olakara
  • 19,223
  • 11
  • 88
  • 133
  • Thanks for the nice explanation, however still an issue for me. Please check the comment I gave to the previous answer (techknowfreak). – TigrouMeow Oct 05 '11 at 08:03
  • sorry, I didn't get you. where is the so called child controller knowing the parent controller? Can you elaborate? There is no interaction started from module controllers to the main controller in the above code. right? or I am understanding you wrong.. :) – Abdel Raoof Olakara Oct 05 '11 at 08:46
  • 1
    Sorry, the child controller doesn't know about the _parent view_ ('centerpane' here). I would like the modules (bunch of controller + views) to be able to be independent. – TigrouMeow Oct 07 '11 at 07:46
1

In main controller add child controller in the click event handler of menu

Ext.define('MyAPP.controller.MainController',{
...
  init:function()
  {
    this.control({
     'menulink':
     {
        click:this.populateCenterPanel
     }
    });
  },
  populateCenterPanel:function()
  {
    this.getController('ChildController');
  }
});

In launch function add listener to controller add event like this -

Ext.application({
...
  launch:function(){
    this.controllers.addListener('add',this.newControllerAdded,this);
  },

  newControllerAdded:function(idx, ctrlr, token){
    ctrlr.init();
  }
});

Now put code for dynamically embedding views in the viewport in init method of ChildController.

Ext.define('MyAPP.controller.ChildController',{
...
  refs: [
    {ref:'displayPanel',selector:'panel[itemId=EmbedHere]'}
  ]
  init:function(){
    var panel=this.getDisplayPanel();
    panel.removeAll();
    panel.add({
      xtype:'mycustomview',
      flex:1,
      autoHeight:true,
      ...
    });
  }
});

HTH :)

Cine
  • 4,255
  • 26
  • 46
  • That's the idea I had as well, problem is I would like to avoid the children controllers to know what is its parent. It's a bit like a baby choosing his parents before to born, right? :p – TigrouMeow Oct 05 '11 at 08:02
  • then use application events...let the main controller fire application event when menu clicked and child controller handle it. – techknowfreak Oct 07 '11 at 14:06
  • 1
    That's what I do now, and I pass the id of the 'main container' to the controller, so that I can use 'this.control' and 'refs' properly. Still I think it's a lot of little tricks, I'd love all that to be managed dynamically by the framework :( – TigrouMeow Oct 12 '11 at 01:07