0
angular.forEach(data.rows, function(value, key){
    var cell = [];
    subId = 0;
    angular.forEach(vm.tableJson, function(value1, key1){       
        if(value1.Type != 'table'){
            if(key == 0){
                vm.columns.push(value1.Name);               
            }
            cell.push(value[value1.Settings[1].Value])
        }
        else{
            reportService.getInnerTableRecords(aaa).then(function(dataRes){ //server call
                angular.forEach(dataRes.rows, function(value2, key2){
                    //some code                     
                })
            })          
        }
    });

}); 

In the above code forEach loop gets completed before getting response from the server.

How to make else case wait until response?

Thanks Chethan

georgeawg
  • 48,608
  • 13
  • 72
  • 95
noname
  • 45
  • 1
  • 1
  • 7

2 Answers2

1

JavaScript is single-threaded. All foreach loops complete before asynchronous APIs resolve results. On the other hand, a foreach loop can push an array of promises that can be used to chain subsequent code:

var promiseArray=[];

angular.forEach(vm.tableJson, function(value1, key1){       
    if(value1.Type != 'table'){
        if(key == 0){
            vm.columns.push(value1.Name);               
        }
        cell.push(value[value1.Settings[1].Value]);
        promiseArray.push(key1);
    }
    else{
        var promise = reportService.getInnerTableRecords(aaa);
        var newPromise = promise.then(function(dataRes){ //server call
            angular.forEach(dataRes.rows, function(value2, key2){
                //some code                     
            })
            return key1;
        });
        promiseArray.push(newPromise);          
    }
});

var compositePromise = $q.all(promiseArray);

return compositePromise.then(function(keyArray) {
    console.log("Number of processed keys = " + keyArray.length);
    //
    //Do subsequent processing here
}).catch(function(error) {
    console.error(error)
    throw error;
});

In the above example the composite promise resolves to an array of the keys for the loop. Each iteration of the loop pushes a promise to an array. The composite promise is created with $q.all. The composite promise is then used to chain subsequent code.

Be sure to return promises from nested levels. Otherwise parent promises will resolve before nested levels complete.

Chaining promises

Because calling the .then method of a promise returns a new derived promise, it is easily possible to create a chain of promises.

It is possible to create chains of any length and since a promise can be resolved with another promise (which will defer its resolution further), it is possible to pause/defer resolution of the promises at any point in the chain. This makes it possible to implement powerful APIs.

--AngularJS $q Service API Reference -- Chaining Promises

Community
  • 1
  • 1
georgeawg
  • 48,608
  • 13
  • 72
  • 95
0

You can use a library such as async to achieve that.

    async.mapSeries(data.rows, function(value, key, firstCallback){
        var cell = [];
        subId = 0;
        async.mapSeries(vm.tableJson, function(value1, key1, secondCallback){       
            if(value1.Type != 'table'){
                if(key == 0){
                    vm.columns.push(value1.Name);               
                }
                cell.push(value[value1.Settings[1].Value])
                secondCallback(null); // iterate next value1
            }
            else{
                reportService.getInnerTableRecords(aaa).then(function(dataRes){ //server call
                    angular.forEach(dataRes.rows, function(value2, key2){
                        //some code                     
                    });

                    secondCallback(null);// iterate next value1
                })          
            }
        }, function () {
            firstCallback(null); // all vm.tableJson completed. iterate next value of data.rows
        });

    }); 

An iterator of async.mapSeries will wait until you call secondCallback and only then go to the next item in vm.tableJson, so you can call it after receiving response from server.

TheSameSon
  • 369
  • 1
  • 9
  • The promise created by `async` are not integrated with the AngularJS framework and its digest cycle. It is likely to cause bug where changes to scope don't trigger AngularJS directives that update the DOM. – georgeawg Mar 02 '17 at 21:55