ExtjsMVC嵌套视图事件和异步函数

Extjs MVC nested views events and async function

本文关键字:异步 函数 事件 嵌套 视图 ExtjsMVC      更新时间:2023-09-26

我正在开发一个extJS 4.2 MVC应用程序。我定义了上下文菜单视图对象:

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

这个上下文菜单是在我创建这个网格(以及其他扩展网格)时构建的:

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');
    }
});

这段代码是从Sencha博客第2点提取的,以避免嵌套对象的内存泄漏。现在在我的控制器中,我想收听

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);
    }
});

在这个控制器中,我调用了另一个控制器函数,我想重新加载"message.Inpinbox"存储:

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();  
                }  
            }
        });
    }
});

在这个函数中,我有一个使用AJAX的异步调用,我想在AJAX响应后重新加载InboxController的存储,但使用这种表示法,控制台会抛出一个错误。是否有调用异步函数并在成功或失败后启动回调的最佳实践?另一个问题是:使用ExtJs MVC监听嵌套视图事件的最佳实践是什么(例如,我的ctxmenu嵌套在网格中)?我为fireevent和bubbleevent读书,但我很困惑。。。请把我带回正确的路。。。

JFYI示例中的上下文菜单没有嵌套在网格中。菜单是浮动对象,因此它们在通常的组件层次之外。

您遇到的错误是,因为您没有向SetMessageStatus传递回调,而是传递表达式this.getStore('message.Inbox').load的结果,该结果的计算结果为一个函数,但如果没有绑定到它的作用域,则这是无用的。阅读此问题的答案,了解更多关于功能范围的解释。

如果采取天真的正面方法,解决方案看起来会很糟糕:

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();
    });
}

然而,更好的方法是使用控制器事件:

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
        });
    }
});

正如您所看到的,通过使用控制器事件,我们将收件箱控制器与消息控制器解耦;它们不再直接调用彼此的方法,而是传递信息。代码要干净得多,而且关注点也得到了适当的分离。