Results 1 to 3 of 3

Thread: Decoupling Controllers

  1. #1
    Sencha User
    Join Date
    Jun 2011
    Location
    Canada
    Posts
    27

    Default Decoupling Controllers

    Hi Everyone,

    I want 1 controller to handle the navigation and three separate controller to handle the 3 views that make up my application. I don't want either of them to know each other, I simply want them to listen to the custom events I am firing from my views.

    How can I say Controller A, listen to events from View A or better yet, Controller A listen for these events, no matter where they came from.

    As I continue my research through the API docs, I thought I would see what others have done in the past; if you need to know, I am using the internal MVC pattern.

  2. #2
    Sencha User
    Join Date
    May 2011
    Location
    Constance, Germany
    Posts
    84

    Default

    In View A (or anywhere else, in another controller or view) you could simple fire a Ext.Dispatcher.dispatch event like this:

    PHP Code:
    Examples.View.MyView Ext.extend(Ext.Panel, {

        
    initComponent: function () {
            var 
    config = {            
                
    dockedItems: [{
                    
    xtype'toolbar',
                    
    dock'top',                
                    
    items: [{
                        
    text'Back',
                        
    itemId'backButton',
                        
    ui'back',
                        
    handlerthis.backHandler,
                        
    scopethis
                    
    }]
                }]
            };
            
    Ext.apply(thisconfig);
            
    Examples.View.MyView.superclass.initComponent.apply(thisarguments);        
        },
        
        
    backHandler: function () {
            
    Ext.dispatch({
                
    controller'Examples.Controller.MyView',
                
    action'goBack'
            
    });
        }
    });

    Ext.regController('Examples.Controller.MyView', {

        
    goBack: function () {
            
    console.log("I have been called, but I don't know the caller!");
        }

    });

    Ext.regController('Examples.Controller.MyOtherController', {

        
    somethingHasHappend: function () {
            
    Ext.dispatch({
                
    controller'Examples.Controller.MyView',
                
    action'goBack'
            
    });
        }
        
    }); 
    The MyView View calls the MyView controller but does not know the instance of the controller. In this case the MyView controller does not know anything about the instance of the MyView view either.
    In addition, the MyOtherController is also able to call the MyView controller without the need to know the instance of the MyView controller.

    Is this loosely coupled enough for you? Otherwise take a lot at the publisher/subscriber pattern.

  3. #3
    Sencha User
    Join Date
    Jun 2011
    Location
    Canada
    Posts
    27

    Default

    Needs a little more... here's a super basic example.

    In some view, there's a button that fire an event called "OMG" and that's it. This button knows nothing of its outside world.

    Then in a galaxy far away, a controller decides to start listening for an event called "OMG". He doesn't know whose firing it or wether it is going to be fired at all. He just says, "ok, i am going to start listening for OMG".

    Here's my code. The following is the controller for my application. When the app launches, it fire the user method because that's the first screen I was people to see. Each controller listens to the events that minupulate the application as a whole, meaning switching between views.
    Code:
    Ext.regController('GeoTrap', {
        defaultOptions: {
            type: 'slide',
            direction: 'right'
        },
    
        user: function (options) {
            $this = this;
            if (!$this.userPanel) {
                $this.userPanel = $this.render({
                    id: 'geo-user',
                    xtype: 'geo-user',
                    listeners:
                    {
                        userNextButton: function ()
                        {
                            $this.destination();
                        }
                    }
                });
            }
    
            var o = options || defaultOptions;
            this.application.viewport.setActiveItem(this.userPanel, 0);
        },
    
        destination: function (options) {
            $this = this;
            if (!$this.destinationPanel) {
                $this.destinationPanel = $this.render({
                    xtype: 'geo-destination',
                    listeners:
                    {
                        destinationBackButton: function ()
                        {
                            $this.user({
                                type: 'slide',
                                direction: 'rigth'
                            });
                        },
                        destinationNextButton: function ()
                        {
                            $this.distance({
                                type: 'slide',
                                direction: 'left'
                            });
                        }
                    }
                });
            }
    
            this.application.viewport.setActiveItem(this.destinationPanel, {
                type: 'slide',
                direction: 'right'
            });
        },
    
        distance: function (options) {
            $this = this;
            if (!$this.distancePanel) {
                $this.distancePanel = $this.render({
                    xtype: 'geo-distance',
                    listeners:
                    {
                        distanceBackButton: function ()
                        {
                            $this.destination();
                        }
                    }
                });
            }
    
            this.application.viewport.setActiveItem(this.distancePanel, {
                type: 'slide',
                direction: 'right'
            });
        }
    });
    What I want to implement now is this: This controller should be listening to events that pertain to only the "Destination" view. The idea is to separate the logic code for the application's viewport and any number of views.

    Code:
    Ext.regController('Destination', {
        index: function (options) {
    
        },
    
        load: function () {
            this.store.load();
        },
    
        get: function () {
    
        },
    
        add: function () {
    
        },
    
        lookup: function () {
    
        }
    });
    Here's the view: the missing link here is what when I fire an event that pertains to only this view, I want the Destination controller to react to it.
    Code:
    GeoTrap.views.GeoDestination = Ext.extend(Ext.Panel, {
        layout: 'fit',
        customEvents: ['destinationBackButton', 'destinationNextButton'],
        initComponent: function () {
            var $this = this;
    
            $this.addEvents($this.customEvents);
    
            this.dockedItems = [{
                xtype: 'toolbar',
                dock: 'top',
                title: 'Pick You Destination',
                items: [
                    {
                        ui: 'light',
                        text: 'Back',
                        handler: function () {
                            $this.fireEvent('destinationBackButton');
                            $this.fireEvent('lookup');
                        }
                    },
                    {
                        xtype: 'spacer'
                    },
                    {
                        ui: 'light',
                        text: 'Distance',
                        handler: function () {
                            $this.fireEvent('destinationNextButton');
                        }
                    }
                ]
            }];
    
            //TODO: Add GeoDestination controller
            //TODO: Add Form with address field
            this.items = [{
                xtype: 'fieldset',
                instructions: 'Enter you destination',
                defaults: {
                    labelWidth: '40%'
                },
                items: [{
                    xtype: 'textfield',
                    label: 'Address',
                    name: 'address',
                    required: true
                }]
            }]
            //TODO: Implement GeoCode lookup
            //TODO: Display map after GeoCode lookup
            //TODO: Add Model & Store and save each location using LocalStorage
    
            GeoTrap.views.GeoDestination.superclass.initComponent.apply(this, arguments);
        }
    });
    
    Ext.reg('geo-destination', GeoTrap.views.GeoDestination);
    I would like to simply tell the Controller, your view is X, listen to its events.

Posting Permissions

  • You may not post new threads
  • You may not post replies
  • You may not post attachments
  • You may not edit your posts
  •