如何在UI5中正确附加和分离事件处理程序

2022-03-09 00:00:00 javascript sapui5

我的自定义控件的数据绑定有问题。

我的控件继承自sap.m.Input,并使用特殊的值helper对其进行扩展。我的新控件的一个新属性是Value Help对话框的一个简单标题。这绑定到I18N模型。

当我现在以正常形式使用我的控件时,一切都可以正常工作。标题已正确绑定,并显示该模型中绑定的I18N属性的值。如果我将我的控件用作sap.ui.table控件列中的模板,它只显示Title属性的默认值。数据绑定似乎不起作用。但仍在处理继承的属性(如值)。

为简化起见,我控件现在只有Title属性,如果请求Value Help,它会在警告框中显示当前值。在表中,显示默认值。并且没有表格,它显示来自I18N模型的绑定值。

这里是简化的控件代码:

sap.ui.define([
  "sap/ui/core/Control",
  "sap/m/Input",
], function(Control, Input) {
  "use strict";

  return Input.extend("DvpClsSuggestInput", {
    "metadata": {
        "properties": {
          // Title of Value-Help Dialog
          "vhTitle": {
            type: "string",
            defaultValue: "Title"
          }
        }
      },
    
      init: function() {
        Input.prototype.init.apply(this, arguments);
        this.setShowValueHelp(true);
        this.attachValueHelpRequest(this.onValueHelpRequest.bind(this));
      },
    
      onValueHelpRequest: function(oEvent) {
        var lvTitle = this.getVhTitle();
        alert(lvTitle);
      },

    });
  });
});

sap.ui.table.Table中的用法(不起作用,显示Title属性的默认值):

<table:Column>
  <m:Label text="{i18gn>HausWaehrung}" />
  <table:template>
    <dvp:MyInput
      value="{ path: 'Inv>Hwaer', type: 'sap.ui.model.type.String' }"
      vhTitle="{i18n>Currency}" />
  </table:template>
</table:column>         

有效的用法:

<VBox>
  <dvp:MyInput
    value="{ path: 'Cls>/Currency', type: 'sap.ui.model.type.String' }"
    vhTitle="{i18n>Currency}" />
</VBox>
同样,针对value属性的绑定在两种情况下都有效。问题只存在于我自己的属性vhTitle。欢迎任何想法。


解决方案

将事件处理程序附加到ManagedObject的事件时,请勿使用.bind。分离事件处理程序也是如此。UI5在这些情况下有自己的记录机制来传递侦听器对象。

示例%1

Attaching/detachingvalueHelpRequest-处理程序使用相应的API并将值传递到参数列表,如API参考中所述:

myInput.attachValueHelpRequest(/*obj?,*/this.onValueHelpRequest, this); // No .bind!
myInput.detachValueHelpRequest(this.onValueHelpRequest, this); // Same references

示例2

将事件处理程序附加到控件实例化,如ManagedObject's API reference中所述(所有控件均为ManagedObjects):

new MyInput({
  // ...,
  valueHelpRequest: [/*obj?,*/this.onValueHelpRequest, this]
});

有效名称和值范围:

  • [.]
  • 对于事件,要么接受函数(事件处理程序),要么是长度为2的数组,其中第一个元素是函数,第二个元素是要调用方法的对象;或者是长度为3的数组,其中第一个元素是任意负载对象,第二个是函数,第三个是调用[.]方法的对象。

示例3(面向控件开发人员)

但是,在控件定义中,可以完全省略侦听器,因为如果没有传递侦听器对象,则事件提供程序本身(即您的控件实例)在默认情况下将成为侦听器。

this.attachValueHelpRequest(this.onValueHelpRequest); // the control instance will be used as the context in that event handler

API reference中也有说明:

如果未指定<;oListener>;,则在事件提供程序的上下文中调用处理程序函数。

在UI5中使用Function.prototype.bind的缺点

  1. 在函数上调用.bind时,创建了一个完整的新函数!

    const myFn = function() {};
    myFn === myFn.bind(); // returns: false
    

    表示如果使用.bind传递处理程序,则该处理程序将变为永远不可分离,因为detachEvent等待与调用attachEvent时相同的函数引用和侦听器对象引用。

  2. 更糟糕的是,使用.bind创建的函数不允许您更改之前传递的thisArg(this),即使EventProvider tries to call之后使用不同的thisArg来更改函数。ECMAScript specification(请参阅注释2)中描述了此限制,也说明了问题中描述的问题的原因。ManagedObject克隆聚合绑定的template控件时,不能覆盖监听器!

相关文章