简体   繁体   中英

Handling multiple Ajax Requests inside another Ajax Request

I'm using angularjs' $http method to get multiple "parent" elements. In this Ajax Calls .success method, I have to iterate over the parent elements, and use yet another Ajax call for every parent element, to get its respective child elements. What I want in the end, is an Array containing all the child element objects, so I can display them using ng-repeat. That's why I want to collect all the child elements in an array first, and the write that array to the scope array I'm using to display, so angular will only update when all child elements are collected. I'm not that versed in using promises, but I think this should be possible by using them. The structure is basically:

.success(function(parentElements){
                    var tempChildElements = [];
                    $.each(parentElements, function(i, parentElement){
                        getChildElements(parentElement)
                            .success(function(childElements){
                                tempChildElements.concat(childElements);
                            })
                        })
                    });
    $scope.childElements = tempChildElements;
});

Basically, I need to know when all the requests inside jQuery.each are finished.

EDIT:

So, I changed my code to incorporate your answers, and I think I'm close but it's still not working. What I got is:

$scope.loadChildren = function(){
            var tempchildren = [];
            var promises = [];
            restApi.getOwnparents() //Returns $http.get promise
                .then(function(parents){

                    parents.data.forEach(function(parent, i, parents){
                        promises.push(restApi.getOwnchildren(parent) //Returns $http.get promise
                            .then(function(children){

                                tempchildren = tempchildren.concat(children.data);
                            },function(msg){
                                console.log(msg);
                            }));

                    });
                }, function(msg){
                    console.log(msg);
                });
            $q.all(promises).then(function(data){
                //Never gets called
                $scope.currentElements = tempchildren;
                console.log(tempchildren);
            });
        };

EDIT 2: I got it to work using suggestions from you guys, below is my code. Feel free to share improvements.

$scope.loadparents = function(){
var tempchildren = [];
var promises = [];
restApi.getOwnparents()
    .then(function(parents){
        parent.data.forEach(function(parent, i, parents){
            promises.push(restApi.getOwnchildren(parent));             
        });
        $q.all(promises).then(function(data){
            console.log(data);
            data.forEach(function(children){
                tempchildren = tempchildren.concat(children.data);
            });
            $scope.currentElements = tempchildren;
        });
    });

};

Something like this might be a possibiliy. Loop through your parentElements calling getChildElements with that element. However the response from getChildElements will be a promise if your returning the $http call so push that into an array and pass that array to $q.all . When all your ajax calls resolve so will $q.all .

 var parentElements = [10, 20, 30, 40],
        promises = [];

    parentElements.forEach(function(i){
        //Each method is actually called here
        promises.push(getChildElements(i));
    });

    //$q.all will resolve once all of your promises have been resolved.
    $q.all(promises)
        .then(function (data){
            //handle success
            console.log('All Good', data);
            //Modify your response into what ever structure you need, map may be helpfull
            $scope.childElements = data.map();
        });

Most likely your ajax call won't be resolved by the time the array is passed to $q.all however another nice thing about promises is even if they are all resolved $q.all will resolve straight away instead.

See it in action. http://jsfiddle.net/ht9wphg8/

Each request itself returns a promise, which can then be put into an array and pass that array to $q.all() .

The success() callback is deprecated and since you need to return promises you need to use then() anyway in your original request callback.

Here's a sample factory that would make all the requests and once done you would have the parent data of first request returned to controller:

app.factory('DataService', function($http, $q) {
  return {
    getData: function() {
      // return initial promise
      return $http.get('parent.json').then(function(resp) {
        var parentArr = resp.data;
        // create array of promises for child data
        var promises = parentArr.map(function(parentItem, i) {
          // return each child request promise to the array
          return $http.get('child.json').then(function(resp) {
            console.log('Child request #' + (i + 1) + ' completed');
            // update parent item
            parentItem.child = resp.data
          });
        });
        // return the promise wrapping array of child promises
        return $q.all(promises).then(function() {
          console.log('All requests completed');
          // when all done we want the parent array returned
          return parentArr;
        });
      });
    }
  };
});

app.controller('MainCtrl', function($scope, DataService) {
  DataService.getData().then(function(parentArr) {
    console.log('Add data to scope')
    $scope.parentArr = parentArr;
  });

});

DEMO

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM