首页 > 解决方案 > 如何限定事件处理程序的形式参数以用于 Fragment.load 承诺解析?

问题描述

如何限定事件处理程序的形式参数以用于 Fragment.load 承诺解析?

我已经构建了一个包含 sap.m.MessagePopover 的 XML 片段。我要求 MessagePopover 能够被任何触发事件的按钮或控件打开。我在基本控制器中创建了事件处理程序。遵循最佳实践,事件处理程序仅在事件发生时才使用 sap.ui.require 加载组件和片段定义。Fragment.load 承诺解析然后通过触发事件的控件打开 MessagePopover。我的问题是我必须在控制器的全局变量中创建对事件源的引用,才能在 sap.ui.require/Fragment.load 范围内使用它。

我的问题是是否可以使用一些承诺/回调魔法让 oEvent 在 Fragment.load 承诺解决方案中可见,所以我不必在控制器中创建全局引用?

PS 请忽略片段应该存储在控制器变量中以供后续调用使用的事实。

这是片段文件

<core:FragmentDefinition
    xmlns="sap.m"
    xmlns:core="sap.ui.core">
    <MessagePopover 
        items="{messages&gt;/}">
        <MessageItem
            activeTitle="{/useActiveTitle}"
            description="{i18n&gt;DESCRIPTION}"
            subtitle="{i18n&gt;SUBTITLE}"
            title="{messages&gt;message}" 
            type="{messages&gt;type}" />
    </MessagePopover>
</core:FragmentDefinition>

在我的测试视图中,我有以下按钮。

<Button
    id="btnViewMessages"
    icon="sap-icon://message-popup"
    press=".onMessageButtonPress"
    text="{= ${messages>/}.length }"
    tooltip="{i18n&gt;VIEW_MESSAGES}"
    type="Emphasized"
    visible="{= ${messages>/}.length > 0}" />

以下是将显示片段的事件处理程序。这是我希望在其中提供 oEvent 的地方.then()

/**
 * Handle a control event to display a MessagePopover next to the control.
 * @function
 * @public
 * @param {sap.ui.base.Event} [oEvent]
 */
 onMessageButtonPress: function (oEvent) {
    // This is where I must to create a reference to the source for later use
    this._oSource = oEvent.getSource();

    sap.ui.require([
        "sap/ui/core/Fragment"
    ], function(Fragment) {
        Fragment.load({
            name: "testControls.view.fragments.MessagePopover"
        })
        .then(function (oFragment) {
            this.getView().addDependent(oFragment);
            // Here I would like to somehow scope oEvent to be able to use it here 
            // instead of having to use the controller's global variable _oSource.
            oFragment.openBy(this._oSource);
        }.bind(this));
    }.bind(this));
 }

为了进行测试,您可以在控制器中使用以下 onInit 来为 MessagePopover 提供可用的消息。

onInit: function () {
    // Set the model for the view
    var oViewModel = new JSONModel();
    oViewModel.setData({
        "useActiveTitle": true
    });
    this.getView().setModel(oViewModel);

    // Setup the MessageManager along with view's message model.
    this._MessageManager = sap.ui.getCore().getMessageManager();
    this.getView().setModel(this._MessageManager.getMessageModel(), "messages");
    this._MessageManager.registerObject(this.getView(), true);
    this._MessageManager.addMessages(
        new Message({
            message: "Enter a valid number for seconds to display busy UI",
            type: library.MessageType.Error,
            target: "/Dummy",
            processor: this.getView().getModel()
    }));
    this._MessageManager.addMessages(
        new Message({
            message: "Fix all errors to coninue",
            type: library.MessageType.Info,
            target: "/Dummy",
            processor: this.getView().getModel()
        }));
}

为了重申我的期望,我想使用oFragment.openBy(oEvent.getSource())控制器的全局变量 _oSource 来代替。

标签: promisescopesapui5

解决方案


不幸的是,事件实例在所有处理程序都有机会处理它之后被重置。因此,当您的 Fragment 承诺被解决时,事件实例由 SAPUI5 ObjectPool 模块重置:您可以在Event.js 实现中看到它(第 74-78 行)。

你可以只使用一个局部变量作为事件源,而不是为这个对象创建一个属性,它将作为闭包的一部分在 Promise 解析中可用:

onMessageButtonPress: function (oEvent) {
    // This is where I must to create a reference to the source for later use
    var oSource = oEvent.getSource();

    sap.ui.require([
        "sap/ui/core/Fragment"
    ], function(Fragment) {
        Fragment.load({
            name: "testControls.view.fragments.MessagePopover"
        })
        .then(function (oFragment) {
            this.getView().addDependent(oFragment);
            // Here I would like to somehow scope oEvent to be able to use it here 
            // instead of having to use the controller's global variable _oSource.
            oFragment.openBy(oSource);
        }.bind(this));
    }.bind(this));
 }

推荐阅读