0

I'm making an AJAX request for each item in a loop, the end REST service can only perform one request at a time so I need the loop to wait for each request to complete before continuing with the next. How do I do this?

For reference, the end service is performing update tasks on DynamoDB tables - only one table can be modified at once hence my requirement to wait until I get a response before continuing. I could send them all to the server in one hit and handle there, although that makes it hard to receive feedback when each update is completed.

angular.forEach($scope.someArray,
  function (value) {

      var postdata = {
        bla: value
      };

      $http.post('/some_url', postdata)
        .then(
        function(result) {
          console.log("Success.");
        },
        function(data) {
          console.log("Failure.");
        }
      );

  }
);
2
  • Can you send the entire array back, and bring back an array with a single request rather than looping? Commented Mar 28, 2014 at 17:54
  • I could do that I guess, but I'd rather do them individually so I can show feedback when each completes. Commented Mar 28, 2014 at 17:56

2 Answers 2

10

Do you really need the forEach? I would not use it and go for something like that:

function req(arr) {
  if (angular.isArray(arr) && arr.length > 0) {
    var postdata = {
      bla: arr[0]
    };
    $http.post('/some_url', postdata)
      .then(
      function(result) {
        console.log("Success.");
        arr.shift();
        req(arr);
      },
      function(data) {
        console.log("Failure.");
        // if you want to continue even if it fails:
        //arr.shift();
        //req(arr);
      }
    );
  }
}
req($scope.someArray);
Sign up to request clarification or add additional context in comments.

2 Comments

req(arr.shift()) will send the shifted value to the next function call and not new array. Your code should be like this : arr.shift(); req(arr);
@PrashantPokhriyal You're right! Thanks for noticing! I updated the answer.
4

If you really must make one request at a time (are you sure there isn't a more efficient alternative?), then you'll have to use something other than Angular.forEach.

What about something like this (you will need to inject $q):

function doWhateverWithAll(someArray) {
  // Mark which request we're currently doing
  var currentRequest = 0;
  // Make this promise based.
  var deferred = $q.deferred();
  // Set up a result array
  var results = []
  function makeNextRequest() {
    // Do whatever you need with the array item.
    var postData = someArray[currentRequest].blah;

    $http.post('some/url', postData)
    .then( function (data){
      // Save the result.
      results.push(data);
      // Increment progress.
      currentRequest++;
      // Continue if there are more items.
      if (currentRequest < someArray.length){
        makeNextRequest();
      }
      // Resolve the promise otherwise.
      else {
        deferred.resolve(results);  
      }  
    });
    // TODO handle errors appropriately.
  }
  // return a promise for the completed requests
  return deferred.promise;
}

Then, in your controller/service, you can do the following:

doWhateverWithAll($scope.someArray)

.then(function(results){
  // deal with results.
});

1 Comment

I'm updating DynamoDB tables - unfortunately only one operation can be done at a time so the only other way would be to post them all and handle the problem on the server. Your solution works well for me needs because I can individually return feedback when each table has been updated.

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.