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

How to scope an event handler's formal parameter for use in a Fragment.load promise resolution?

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

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

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

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

这是片段文件

<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}" />

以下是将显示片段的事件处理程序。这是我希望在 .then()

内提供 oEvent 的地方
/**
 * 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。

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

您可以只使用一个局部变量作为事件源,而不是创建一个 属性 到 this 对象,它将作为闭包的一部分在 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));
 }