Extjs MVC nested views events and async function

I'm developing an extJS 4.2 MVC app. I've this context menu view object defined:

Ext.define('XApp.view.message.inbox.CtxMenu', {
    extend : 'Ext.menu.Menu',
    alias : 'widget.inboxctxmenu',
    items : [ {
        itemId : 'buttonSetFlags',
        text : 'ToRead'
    }]
});

this context menu is builded when i'm creating this grid (and other my extended grids):

Ext.define('XApp.view.message.inbox.Grid', {
    extend: 'Ext.grid.Panel',
    alias: 'widget.inboxgrid',
    store: 'message.Inbox',

    initComponent : function(){
        this.menu = this.buildMenu();
        this.callParent(arguments);
        this.on({
            scope : this,
            itemcontextmenu : this.onItemContextMenu
        });
    },

    onItemContextMenu : function(grid, record, item, index, e, eOpts) {
        console.log('onItemContextMenu');
        e.stopEvent();      
        this.menu.showAt(e.getXY());
    },

    onDestroy : function(){
        console.log('destroy grid and menu');
        this.menu.destroy();
        this.callParent(arguments);
    },

    buildMenu : function(){
        return Ext.widget('inboxctxmenu');
    }
});

this code is extracted from Sencha blog on point 2 to avoid memory leak on nested object. Now in my controller i want to listen

Ext.define('XApp.controller.Inbox', {
    extend : 'Ext.app.Controller',

    init : function(application) {
        this.control({
            "inboxctxmenu #buttonSetFlags" : {
                click : this.onFlagsSetter
            }
        });
    },
    onFlagsSetter : function(button, e, eOpts) {
        this.getController('Message').SetMessageStatus(1,"ToRead",this.getStore('message.Inbox').load);
    }
});

in this controller, i call another controller function and i want to reload 'message.Inbox' store:

Ext.define('XApp.controller.Message', {
    extend : 'Ext.app.Controller',

    SetMessageStatus: function(id,statusToSet,callback) {
        Ext.Ajax.request({
            url : XApp.util.Util.serverUrl + 'api/message/SetMessageStatus/' + id + "/" + statusToSet,
            method : "GET",
            failure : function(response, options) {
                console.log('Failure' + response);
            },
            success : function(conn, response, options, eOpts) {
                console.log('Success');
                if (callback && typeof(callback) === "function") {  
                    console.log('Calling callback');
                    callback();  
                }  
            }
        });
    }
});

in this function, i've an async call with AJAX, and i want to reload store of InboxController after ajax response, but with this notation, console throw an error. There are best practices to call async function and launch a callback after success or failure? Another question is: what is the best pratices with ExtJs MVC to listen on nested view event (in example my ctxmenu is nested in a grid)? i read for fireevent and bubbleevent but i'm confused...Please bring me back to the right way...


JFYI the context menu in your example is not nested in the grid. Menus are floating objects, and as such they are outside of the usual component hierarchy.

The error you're having is because you're not passing a callback to SetMessageStatus , you're passing the result of expression this.getStore('message.Inbox').load - which evaluates to a function, but without a scope bound to it it's useless. Read this question's answers for more explanations on what the function scope is.

With a naïve head-on approach, the fix would look thusly:

onFlagsSetter: function(button, e) {
    var me = this; // Important for the closure below

    this.getController('Message').SetMessageStatus(1, 'ToRead', function() {
        // Note that within the callback function, `this` is an object
        // entirely different from `this` in the above line, so we call
        // `getStore` on the captured scope instead.
        me.getStore('message.Inbox').load();
    });
}

However, a much better approach is to use Controller events:

Ext.define('XApp.controller.Inbox', {
    extend: 'Ext.app.Controller',

    init: function() {
        this.listen({
            component: {
                'inboxctxmenu #buttonSetFlags': {
                    click: this.onFlagsSetter
                }
            },
            controller: {
                '*': {
                    statusmessage: this.onStatusMessage
                }
            }
        });
    },

    onFlagsSetter: function(button) {
        this.fireEvent('setstatus', 1, 'ToRead');
    },

    onStatusMessage: function(success, response) {
        if (success) {
            this.getStore('message.Inbox').load();
        }
    }
});

Ext.define('Xapp.controller.Message', {
    extend: 'Ext.app.Controller',

    init: function() {
        this.listen({
            controller: {
                '*': {
                    setstatus: this.setMessageStatus
                }
            }
        });
    },

    setMessageStatus: function(id, statusToSet) {
        Ext.Ajax.request({
            url: ...,
            method: 'GET',

            failure: function(response) {
                this.fireEvent('statusmessage', false, response);
            },

            success: function(connection, response) {
                this.fireEvent('statusmessage', true, response);
            },

            // We are setting the above callbacks' scope to `this` here,
            // so they would be bound to the Controller instance
            scope: this
        });
    }
});

As you can see, by using Controller events we have decoupled Inbox controller from the Message controller; they are no longer calling each other's methods directly but are passing information instead. The code is much cleaner, and concerns are properly separated.

链接地址: http://www.djcxy.com/p/76400.html

上一篇: 在Extjs应用程序中,控制器如何与MVC一起使用

下一篇: Extjs MVC嵌套视图事件和异步函数