1

One of my tables does not load data and throws some error for one of the OData model as undefined.

<script id="sap-ui-bootstrap"
  src="/resources/sap-ui-core.js"
  data-sap-ui-libs="sap.m, sap.uxap, sap.ui.table"
  data-sap-ui-theme="sap_bluecrystal"
  data-sap-ui-compatVersion="edge"
  data-sap-ui-preload="async"
  data-sap-ui-resourceroots='{"com.ABC": ""}'
  data-sap-ui-xx-bindingSyntax="complex"
></script>

Controller.js

_initializeData: function() {
  var parts = {};
  parts.PartsByKey = "SP";
  parts.PriceColumn = false;
  parts.SubTotalColumn = false;
  this.orderMaterialsModel = new JSONModel(Parts);
  this.getView().setModel(this.orderMaterialsModel, "orderParts"); //Line number 6
  this.orderMaterialsModel.setProperty("/OrdersTotal", 0);
  /* works fine till here. But moment above statement is executed,
  the execution goes to the below formatter. The model which is 
  initialized in the next line is never executed, and then the
  formatter throws error - model undefined */
  this.salesOrderModel = this.getOwnerComponent().getModel("salesOrderModel");
  this._validationChecks(this.salesOrderModel.getData());
  this.getView().getModel("salesOrderModel").refresh(false);
  //...
},

// Formatter function for the table rows
formatQty: function(QOH, qty) {
  var oType = this.salesOrderModel.oData.type;
  // error here as this.salesOrderModel does not exists..
},
Boghyon Hoffmann
  • 17,103
  • 12
  • 72
  • 170
THI
  • 355
  • 11
  • 40

1 Answers1

2

When setting the /OrdersTotal value, do it asynchronously:

this.orderMaterialsModel.setProperty("/OrdersTotal", 0, /*context*/null, /*async*/true );

Explanation

Somewhere in your view definition, you must have bound /OrdersTotal with the formatter: '.formatQty'. Calling setProperty without true at the end triggers all dependent listeners first (incl. the formatter), and then the rest of the code continues.

Synchronous execution:

  1. In _initializeData:

    // ...
    this.orderMaterialsModel.setProperty("/OrdersTotal", 0);
    
  2. In formatQty:

    var oType = this.salesOrderModel.oData.type; // Error! this.salesOrderModel is undefined
    // ...
    
  3. Continue _initializeData with:

    this.salesOrderModel = this.getOwnerComponent().getModel("salesOrderModel");
    // ...
    

Passing true as the fourth argument in setPropertyAPI will make sure that the remaining code lines in _initializeData are handled first, and all the dependent listeners will be put as the last task to be processed in the call stack.

Asynchronous execution:

  1. In _initializeData:

    this.orderMaterialsModel.setProperty("/OrdersTotal", 0, null, true);
    this.salesOrderModel = this.getOwnerComponent().getModel("salesOrderModel");
    //...
    
  2. In formatQty:

    var oType = this.salesOrderModel.oData.type;
    // ...
    

Another issue is that the listeners (e.g. the formatter) will also get triggered when the model is just set.

You can postpone the trigger by setting the model at the end of the callstack, just like the case with async setProperty, by using requestAnimationFrame

// ...
window.requestAnimationFrame(function() {
  this.getView().setModel(this.orderMaterialsModel, "orderParts");
  // triggers the formatter
}.bind(this));
// ...
Boghyon Hoffmann
  • 17,103
  • 12
  • 72
  • 170