How to make synchronous AJAX requests in AngularJS controller

19,417

Solution 1

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

Solution 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

Share:
19,417
lys1030
Author by

lys1030

Updated on August 21, 2022

Comments

  • lys1030
    lys1030 over 1 year

    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!