UI5:格式化程序从 XML 视图调用多次或过早

UI5: Formatter called multiple times or too soon from an XML view

我正在使用 OpenUI5。使用 formatter.js,我在视图中格式化了一些文本。

但是我的格式化程序被调用了 3 次:

  1. 当我将模型绑定到面板控件时:oPanel.setModel(oModel, "data"); sBirthdaysFormat 都是 undefined.

  2. onInit()完成并渲染视图后: sBirthday 正确定值,sFormatundefined

  3. 再次强调:sBirthdaysFormat 均已正确定价。

为什么会这样?正确吗?
应用出现错误,因为格式化程序中的 ageDescription() 无法管理 undefined 值。

formatter.js

sap.ui.define([], function () {
  "use strict";

  return {
    ageDescription : function (sBirthday, sFormat) {
      do.something();
      var sFromMyBd = moment(sBirthday, sFormat).fromNow();
      do.something();
      return sAge;
    }
  }
});

main.view.xml

<mvc:View
  controllerName="controller.main"
  xmlns="sap.m"
  xmlns:mvc="sap.ui.core.mvc">
  <Panel id="user-panel-id">
    <Input id="name-input-id" enabled="false" value="{data>/user/name}" />
    <Label text="{i18n>age}: " class="sapUiSmallMargin"/>
    <Label text="{
      parts: [
        {path: 'data>/user/birthday'},
        {path: 'data>/user/dateFormat'}
      ],
      formatter: '.formatter.ageDescription' }"/>
  </Panel>
</mvc:View>

Main.controller.js

sap.ui.define([
  "sap/ui/core/mvc/Controller",
  "sap/ui/model/json/JSONModel",
  "model/formatter"
], function (Controller, JSONModel, formatter) {
  "use strict";

  return Controller.extend("controller.main", {
    formatter: formatter,
    onInit: function () {
      var oModel = new JSONModel();
      var oView = this.getView();
      oModel.loadData("model/data.json");
      var oPanel = oView.byId("user-panel-id");
      oPanel.setModel(oModel,"data");
      do.something();
    },
  });
});

data.json

{
  "user": {
    "name": "Frank",
    "surname": "Jhonson",
    "birthday": "23/03/1988",
    "dateFormat": "DD/MM/YYYY",
    "enabled": true,
    "address": {
      "street": "Minnesota street",
      "city": "San Francisco",
      "zip": "94112",
      "country": "California"
    }
  }
}
  • 仅在数据请求完成时将模型设置为视图:

    onInit: function() {
      const dataUri = sap.ui.require.toUri("<myNamespace>/model/data.json");
      const model = new JSONModel(dataUri);
      model.attachEventOnce("requestCompleted", function() {
        this.getView().setModel(model);
      }, this);
      // ...
    },
    

    这确保格式化程序只被调用一次(由 checkUpdate(<strong>true</strong>) 调用,发生在绑定初始化时;见下文) ,之后没有检测到进一步的变化。

  • 此外(或备选),使格式化程序更具防御性。类似于:

    function(value1, value2) {
      let result = "";
      if (value1 && value2) {
        // format accordingly ...
      }
      return result;
    }
    

Why does this happen?

  1. 视图被实例化。
  2. 控制器的
  3. onInit 被调用。此处,请求文件 model/data.json(模型为空)。
  4. 将视图添加到 UI 后,UI5 传播现有父视图 模型到视图。
  5. 视图内的绑定被初始化,触发checkUpdate(/*forceUpdate*/<strong>true</strong>)src 在每一个中。
  6. 由于 forceUpdate 标志被激活,change 事件被触发,即使根本没有任何变化也会强制触发格式化程序:
    [undefined, undefined][undefined, undefined]。 - 第一次格式化程序调用
  7. 获取 model/data.json 现已完成。现在模型需要再次checkUpdate
  8. [undefined, undefined][value1, undefined] → 检测到更改 → 2nd 格式化程序调用
  9. [value1, undefined][value1, value2] → 检测到更改 → 3rd 格式化程序调用

现在,鉴于您正在尝试将静态 JSON 文件加载到您的项目中,最好最大限度地利用 manifest.json

这样,您就可以确定在任何绑定之前数据已经加载并在模型中可用。

您可以通过将 JSON 文件作为 数据源 添加到 sap.app[=21 下来实现此目的=]

manifest.json

"sap.app": {
    "id": "com.sample.app",
    "type": "application",
    "dataSources": {
        "data": {
            "type": "JSON",
            "uri": "model/data.json"
        }
    }
}

现在,只需将这个名为 datadataSource 添加为 sap.ui5 下的 models 之一。

"sap.ui5": {
    "rootView": {
        "viewName": "com.sample.app.view.App",
        "type": "XML"
    },
    "models": {
        "i18n": {
            "type": "sap.ui.model.resource.ResourceModel",
            "settings": {
                "bundleName": "com.app.sample.i18n.i18n"
            }
        },
        "data": {
            "type": "sap.ui.model.json.JSONModel",
            "dataSource": "data"
        }
    }
}

有了这个,你不需要再调用它了:

var oModel = new JSONModel();
var oView = this.getView();
oModel.loadData("model/data.json");
var oPanel = oView.byId("user-panel-id");
oPanel.setModel(oModel,"data"); 

..因为我们在 manifest.json 中添加的 data model 从一开始就已经对 oViewoPanel 可见。

这样,格式化程序是否被多次调用并不重要,因为它从一开始就已经拥有可用的数据。