【问题标题】:UI5: Formatter called multiple times or too soon from an XML viewUI5:从 XML 视图多次或过早调用格式化程序
【发布时间】:2020-03-06 23:43:31
【问题描述】:

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

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

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

  2. onInit() 完成并渲染视图后: sBirthday 被正确估价,sFormatundefined

  3. 再次重申:sBirthdaysFormat ara 均正确估价。

为什么会这样?对吗?
应用程序出错,因为格式化程序中的 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;
    }
  }
});

ma​​in.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"
    }
  }
}

【问题讨论】:

    标签: data-binding sapui5 formatter


    【解决方案1】:
    • 只有在数据请求完成时才将模型设置为视图:

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

    为什么会这样?

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

    【讨论】:

      【解决方案2】:

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

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

      您可以通过将 JSON 文件添加为 sap.app

      下的 数据源 来实现此目的

      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 可见。

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

      【讨论】:

      • 也想提出同样的建议,但在测试时,我意识到 UI5 实际上并没有等待模型数据被加载。 它恰好工作了很多次因为数据负载通常很小,但是一旦它变大或出现延迟问题,格式化程序就会被再次调用多次。
      • 嗯,是的,我明白你的意思。我确实假设他的数据负载确实很小,因为他的data.json 似乎正在加载单个“用户”。无论如何,对于更大的数据集,我也可能会选择类似于您的解决方案 Boghyon 的东西。感谢您指出这一点。
      猜你喜欢
      • 2020-08-10
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2010-10-03
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多