5

In manifest.json, I have following model definition:

{
    "sap.ui5": {
        "models": {
            "SalesInvoices": {
                "type": "sap.ui.model.odata.v2.ODataModel",
                "settings": {
                    "defaultOperationMode": "Server",
                    "defaultCountMode": "Request"
                },
                "dataSource": "ZAM_SALES_STATISTICS_CDS",
                "preload": true
            }
        }
    }
}

As you can see, SalesInvoices is connected to the OData service.

Now on the onInit function in the controller, I am trying to get Metadata from OData as following:

{ // Controller
    onInit: function() {
        const oPayerModel = this.getView().getModel("SalesInvoices");
        console.log(oPayerModel.getMetadata());
        setTimeout(() => {
            const oPayerModel = this.getView().getModel("SalesInvoices");
            console.log(oPayerModel.getMetadata());
        }, 600);
    },
    // ...
}

As you can see, I have to delay to get the OData instance.
setTimeout is not recommended to use in SAPUI5, how can I do it better?

Boghyon Hoffmann
  • 17,103
  • 12
  • 72
  • 170
softshipper
  • 32,463
  • 51
  • 192
  • 400

2 Answers2

7

You can avoid setTimeout, as mentioned in this answer, by using the v2.ODataModel API metadataLoaded instead which returns a promise. The promise is fulfilled once the service metadata is loaded successfully.

onInit: async function() {
  const oPayerModel = this.getOwnerComponent().getModel("SalesInvoices");
  try {
    await oPayerModel.metadataLoaded(true);
    const oServiceMetadata = oPayerModel.getServiceMetadata(); // NOT .getMetadata()
    // ...
  } catch (oError) {/* ... */}
},

About the model being undefined in onInit, here are answers with better explanations:

Boghyon Hoffmann
  • 17,103
  • 12
  • 72
  • 170
  • The object `oPayerModel` is undefined on `const oPayerModel = this.getView().getModel("SalesInvoices");`, that why I use `setTimeout()`, because of the delay. Why `oPayerModel` is undefined? – softshipper Jan 23 '18 at 08:05
  • 1
    @zero_coding So that's the actual problem. It would've been nice if you could've mentioned that in your question. Anyhow, my fault since I overlooked that. As [mentioned by Nabi](https://stackoverflow.com/a/48397461/5846045) or [in my other answer](https://stackoverflow.com/a/42251431/5846045), replace `.getView().getModel` with `.getOwnerComponent().getModel`. The reason for that is that the view doesn't know its parent yet in `onInit`. So the model from the component (defined in manifest) isn't propagated to the view yet. – Boghyon Hoffmann Jan 23 '18 at 09:20
5

I think you are running into the issue I reported some time ago: Component + default OData model: this.getView().getModel() returns undefined in onInit() of controllers:

  • don't use this.getView().getModel() directly in onInit()
  • instead use this.getOwnerComponent().getModel() in onInit()
  • anywhere else in the controller you can use this.getView().getModel()

In your case you should be fine changing the suggestion of @boghyon slightly:

onInit: function() {
  const oPayerModel = this.getOwnerComponent().getModel("SalesInvoices");
  oPayerModel.metadataLoaded().then(this.onMetadataLoaded.bind(this, oPayerModel));
},

onMetadataLoaded: function(myODataModel) {
  const metadata = myODataModel.getServiceMetadata(); // NOT .getMetadata()
  // ...
},

This way you can get rid of setTimeout(...).

Nabi
  • 2,536
  • 1
  • 16
  • 18