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

非 Y 不嫁゛ 提交于 2019-12-07 02:55:44
  • Set the model to the view only when the data request is completed:

    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);
      // ...
    },
    

    This ensures that the formatter is called only once (invoked by checkUpdate(true) which happens on binding initialization; see below), and no further changes are detected afterwards.

  • Additionally (or alternatively), make the formatter more defensive. Something like:

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

Why does this happen?

  1. View gets instantiated.
  2. onInit of the Controller gets invoked. Here, the file model/data.json is requested (model is empty).
  3. Upon adding the view to the UI, UI5 propagates existing parent models to the view.
  4. Bindings within the view are initialized, triggering checkUpdate(/*forceUpdate*/true)src in each one of them.
  5. Due to the forceUpdate flag activated, change event is fired, which forcefully triggers the formatters even if there were no changes at all:
    [undefined, undefined][undefined, undefined]. - 1st formatter call
  6. Fetching model/data.json is now completed. Now the model needs to checkUpdate again.
  7. [undefined, undefined][value1, undefined] → change detected → 2nd formatter call
  8. [value1, undefined][value1, value2] → change detected → 3rd formatter call

Now, given that you are trying to load a static JSON file into your project, it's better to maximize the usage of the manifest.json.

That way, you are sure that the data is already loaded and available in the model prior to any binding.

You achieve this by adding the JSON file as a data source under sap.app

manifest.json

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

Now, simply add this dataSource called data as one of the models under sap.ui5.

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

With this, you DON'T need to call this anymore:

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

..as the data model we added in the manifest.json, is already visible to oView and oPanel right from the get go.

This way, it doesn't matter if the formatter gets called multiple times, as it would already have the data available to it right from the beginning.

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!