Reputation: 5463
I maintain an SAP Fiori app that has been running for two years without any problems. After upgrading SAPUI5 from 1.56.x to 1.101.x, there are various errors that can be traced back to a place where I try to load data for a JSON model.
The error is:
Uncaught (in promise) TypeError: Cannot read properties of undefined (reading 'indexOf')
This is the code:
onAfterRendering: function (oEvent) {
var sButtonId = this.getModel("misc").getProperty("/ButtonId");
// ...
// Here the code breaks because the variable is undefined:
if (sButtonId.indexOf("Demand") > -1) {
//...
}
},
The error usually only appears when navigating to the app from the SAP Fiori launchpad. If you reload the app itself, 99.9% of the time no error occurs.
There is no call that describes or reads the variable beforehand. The error appears directly at the first use.
I was trying to debug the UI5 framework a bit and came across internal method JSONModel.prototype._getObject
:
When I call the app directly, this method returns the appropriate data and the app works. When I call the app from the launchpad, the method returns null
. The model has not been loaded yet (oNode === undefined
).
I then looked at the network and found that when I call the app directly, the JSON file/model has already been loaded before the above function is called, whereas when I load the app from the launchpad, the JSON file has been requested but no content has been served yet.
So it seems to be an asynchronous problem. I cannot use async
/await
, because UI5 officially only supports ECMAScript 5 (ES5) and we cannot deploy otherwise.
The model is declared and preloaded via the app descriptor (manifest.json
).
Upvotes: 2
Views: 1027
Reputation: 18064
Same as a/61879725 or a/63892279, you'll need to refactor the code by using dataLoaded
1 from the JSONModel
to ensure that the data have been loaded:
// Given: JSONModel and data source declared in the application descriptor (manifest.json)
thatJSONModel.dataLoaded().then(function() { // Ensuring data availability instead of assuming it.
var sButtonId = thatJSONModel.getProperty("/ButtonId"); // sButtonId is now defined.
// ...
}.bind(this));
Btw. I'd strongly discourage applications from relying on onBeforeRendering
/onAfterRendering
since it's unpredictable for them when and how many times the framework or a control initiates rendering.2
1 API Reference: sap.ui.model.json.JSONModel#dataLoaded
2 For example, the recent commit 8e24738
reduces the number of render calls in applications.
Upvotes: 4