4

I've been told that $http in Angular is asynchronous. However, for some purpose, I need to make sequential AJAX requests. I want to read all the files from a file list, and then get the number from all those files. For example:

content of "fileNames":

file1
file2

content of "file1":

1

content of "file2":

2

The following code will calculate the sum

<!DOCTYPE html>
<html>
<body>
<p id="id01"></p>
<script src="http://code.jquery.com/jquery-1.11.3.min.js"></script>
<script>

var fileString;
/* first AJAX call */
$.ajax({
    url: 'fileNames', type: 'get', async: false,
    success: function(content) {
        fileString = content;
    }
});
var fileList = fileString.split('\n');
var sum = 0;
for (var i = 0; i < fileList.length; i++) {
      /* second AJAX call in getNumber function */
      sum += getNumber(fileList[i]);
}
document.getElementById("id01").innerHTML = sum;

function getNumber(file) {
    var num;
    $.ajax({url: file, type: 'get', async: false,
      success: function(content) {
            num = content;
        }
    });
    return parseInt(num);
}

</script>
</body>
</html>

Since the two $.ajax calls are sequential, I don't know how to achieve this functionality in AngularJS. Say, in the end, I want $scope.sum = 1 + 2.

Can someone make it work in AngularJS? Some simple code would be appreciated!

1
  • i wrote a factory about it, check it out link Commented Jan 8, 2017 at 7:32

4 Answers 4

3

You could make use of promises and promise chaining (with $q and the promise returned by $http). Example: In your controller you could do (after injecting $http, $q):

angular.module('myApp').controller('MyCtrl', ['$http','$q','$scope', function($http, $q, $scope){

    function getData(){
        //return promise from initial call
         return $http.get('fileNames')
                .then(processFile) //once that is done call to process each file
                .then(calculateSum);// return sum calculation
      }

      function processFile(response){
         var fileList = response.data.split('\n');
          //Use $q.all to catch all fulfill array of promises
          return $q.all(fileList.map(function(file){
             return getNumber(file);
          }));
      }

      function getNumber(file) {
          //return promise of the specific file response and converting its value to int
          return $http.get(file).then(function(response){
             return parseInt(response.data, 10);
          });

          //if the call fails may be you want to return 0? then use below
          /* return $http.get(file).then(function(response){
             return parseInt(response.data, 10);
          },function(){ return 0 });*/
      }

      function calculateSum(arrNum){
          return arrNum.reduce(function(n1,n2){
             return n1 + n2;
          });
      }

      getData().then(function(sum){
         $scope.sum = sum;
      }).catch(function(){
         //Oops one of more file load call failed
      });

}]);

Also see:

  • $http
  • $q
  • $q.all
  • Array.map - You could as well manually loop though the array and push promise to array.
  • Array.reduce - You could as well loop through number and add them up.

This does not mean that the calls are synchronous, but they are asynchronous and still does what you need in a more efficient way and easy to manage.

Demo

Sign up to request clarification or add additional context in comments.

3 Comments

Thanks for your answer and demo! This is exactly what I want.
@user3796566 you are welcome. I would suggest rather than taking the solution as is try it out yourself, read through the docs to understand better . All the best
It seems $http.get(file).then(...) does not work for json files. Could you please see this demo? link. Thanks in advance!
2

The other answers show how you properly use $http in an Asynchronous manner using promises or what is also called chaining, and that is the correct way of using $http. Trying to do that Synchronously as you have asked will block the Controller's cycle which is something you never want to do.

Still you can do the terrible thing of checking status of a promise in a loop. That can be done by the $$state property of the promise which has a property named status

Comments

0

You can use the promise that is returned by $http method calls:

//Do some request
$http.get("someurl")
//on resolve call processSomeUrlResponse
.then(processSomeUrlResponse)
//then do another request
.then(function(){
   return $http.get("anotherurl").then(processAnotherUrlResponse);
})
//when previous request is resolved then do another 
.then(function(){
   return $http.get("yetanotherurl").then(processYetAnotherUrlResponse);
})
//and do another
.then(function(){
   return $http.get("urls").then(processUrlResponse);
});

When you return a promise in a then callback the next then will not be called till the promise has been resolved.

Angular's $q(deferred/promise) service

Comments

0

It is possible with angular http functions using promises. E.G:

$scope.functionA = function(){
    return $q(function(resolve){
        resolve("theAnswertoallquestions");
    });
}

$scope.functionB = function(A){
    return $q(function(resolve);
        $http.get("URLRoot/" + A).success(function(){resolve();});
    });
}

$scope.functionC = function(){
    return $q(function(resolve);
        resolve("I AM THE LAST TO EXEGGCUTE!!!");
    });
}

$scope.allTogetherNow = function(){
    var promise = $scope.functionA();
    promise.then(function(A){
        return $scope.functionB(A);
    }).then(function(){
        return $scope.functionC();
    }).then(function(){ 
        return "ALL DONE"
    });
}

$scope.allTogetherNow();

1 Comment

.... well i just tried producing the simplest code possible. You can of course put ajax calls inside those and only have it return resolve on a success call, and that would produce what you want. Curse these other smart people getting in their better answers before me... I just want enough points to write comments on other people's stuff!

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.