cancel
Showing results for 
Search instead for 
Did you mean: 

Recommendations for how to call oModel.read due to the async nature of it.

0 Kudos

Hello community experts,

I am invoking an odata read call which fetches me a set of data. In order to complete my data set I need to make subsequent read calls to another odata service passing in input from the first read call. However, I (think I) need to call the second read call in a loop to fetch the relevant data. Here is an example of what I'm doing:

oModel.read("/myService", {
   success: function(oData) {
      var dataArray = oData.array;
      for (var i = 0; i < dataArray.length; i++) {
         var dataRow = dataArray[i];
         for (var j = 0; j < dataRow.length; j++) {
            oModel.read("/nextService('" + dataRow[j].input + "')", {
               success: function(oData) {
                  dataRow[j].element = oData.sVar;
               },
               error: function(oError) {
               }
            });
            dataArray[i].dataRow = dataRow; // might not be necessary, but I have tried without it too.
         }
      }
   },
   error: function(oError) {
   }
});

I'm most likely guessing that what I'm attempting is bad practice, not recommended etc etc. I get all that, I don't know or understand enough about the lifecycle of the app and the async nature of the ODataModel to know how to tackle this and so need the communities input. Bottom line is, I need for a way to get data from one read call (works) and loop through and pass input to make subsequent read calls to a second service from which the data retrieved will be assigned back to an array from the first call (which is missing). During debugging I found that both 'for loops' complete running before the second read call even completes once (due to async). I have also tried implementing the function 'attachRequestCompleted' but that didn't solve it for me. What am I doing wrong and what is the best practice to achieve what I need?

Thanks

D.

View Entire Topic
ricardo7227
Participant
0 Kudos

I don't know if this can help you, but using promises can take some of the complexity out of the code, at least in the first sequence.

https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Promise

For example we can do this:

convert calls to promises:

  firstCall: function () {
            return new Promise((fResolve, fReject) => {

                this.getModel().read("/myService", {
                    success: oResponse => {
                        fResolve(oResponse);
                    },
                    error: oResponse => {
                        fReject(oResponse);
                    }
                });
            });
        },

        secondCall: function (sCode) {
            return new Promise((fResolve, fReject) => {

                this.getModel().read("/nextService('" + sCode + "')", {
                    success: oResponse => {
                        fResolve(oResponse);
                    },
                    error: oResponse => {
                        fReject(oResponse);
                    }
                });
            });
        },

We can now apply them in the following way:

this.firstCall().then(oResponse => {
                //One call to the second service

                //logic to extract the code
                let sCode = oResponse.ValueX;

                this.secondCall(sCode).then(oResponse => {
                    //result second call

                }).catch(oResponse => {
                    //error second call
                    console.log(oResponse);
                });

                //Multiple calls to the second service

                // You can also group calls with Promise.all.
                let aResponse = oResponse.mArray;
                let aSecondCallPromise = [];
                aResponse.forEach(sKey => {
                    let oPromiseTemp = this.secondCall(sKey);
                    aSecondCallPromise.push(oPromiseTemp);
                });

                Promise.all(aSecondCallPromise).then(aResponse => {
                    //we reach this point when all calls are completed.

                }).catch(oResponse => {
                    console.log(oResponse);
                });


            }).catch(oResponse => {
                //first call error
                console.log(oResponse);
            });


Greetings.

0 Kudos

Hello Ricardo,

Thank you for your detailed response on Promises.

I tried out your suggestion but the result is the exact same as what happens in the scenario I tried without promises. Here is the code:

onInit: function() {
   oModel.read("/firstService", {
      success: function(oData, oResponse) {
         var dataArray = oData.array;
         for (var i = 0; i < dataArray.length; i++) {
            var dataRow = dataArray[i];
            for (var j = 0; j < dataRow.length; j++) {
               var input = dataRow[j].input; // console.log here reveal all values are the last array element
               this.getDataValue(input, oModel).then(oData => {
                  dataRow[j].element = oData.sVar;
               }
            }
         }
      }.bind(this),  
      error: function(oError) {
         // handle
      }
   });
},

getDataValue: function(input, oModel) {
   return new Promise((fResolve, fReject) => {
      oModel.read("/nextService('" + input + "')", {
         success: function(oData, oResponse) {
            fResolve(oData);
         },
         error: function(oError) {
            fReject(oError);
         }
      });
   });
}

What am I doing incorrectly above?

In the second for loop, I found that the output is always the last element of the dataRow from dataArray[0] indicating that i never got incremented. But I also noticed by using console.log in the first for loop, that it does increment properly and go through both for loops cycles properly. So wondering what's going on and if anyone has seen such behavior before? Promises did sound promising (!) in that it might solve the async nature of wanting to call a second oData service to fetch addtional values for line items returned from a first Odata service call. I can't find out how to achieve this.

D.