I'm using OpenUI5. Using the formatter.js
, I have formatted some text in my view.
But my formatter is called 3 times:
When I bind the model to panel control: oPanel.setModel(oModel, "data");
both sBirthday
and sFormat
are undefined
.
After onInit()
is finished and the view is rendered:
sBirthday
is valorized correctly and sFormat
is undefined
Again: both sBirthday
and sFormat
ara valorized correctly.
Why does this happen? Is it correct?
The app get an error, because the ageDescription()
in the formatter, can't manage undefined
values.
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"
}
}
}
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?
onInit
of the Controller gets invoked. Here, the file model/data.json
is requested (model is empty).checkUpdate(/*forceUpdate*/true)
src in each one of them.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 callmodel/data.json
is now completed. Now the model needs to checkUpdate
again.[undefined, undefined]
→ [value1, undefined]
→ change detected → 2nd formatter call[value1, undefined]
→ [value1, value2]
→ change detected → 3rd formatter call