0

I have a service that do two $http.get to get data from two source and concat into an array and return it to controller.

angular.module('starter.controllers').factory('GetDataList', function ($http) {
var arrDataList = [];
var postData1 = {
    "param": "1"
};

var postData2 = {
    "param": "2"
};

$http({
    method: 'GET',
    url: 'https://localhost/search',
    data: postData1
})
.then(function (items) {
    debugger
    arrDataList = arrDataList.concat(items.data.list);
});

$http({
    method: 'GET',
    url: 'https://localhost/locate',
    data: postData2
})
   .then(function (items) {
   debugger
   arrDataList = arrDataList.concat(items.data.list);
   });

return {
    getAPIData: function () {
        debugger
        return arrDataList;
    }
};
});

In my controller, I call it like this:

$scope.GetList = function () {
   debugger
   $scope.item = GetDataList.getAPIData();

   $scope.$broadcast('scroll.infiniteScrollComplete');
}

When I use the debugger in console, I notice that

1) getAPIData() will be called first but it has data in it

2) Next debugger triggered at the controller which GetDataList.getAPIData(); does not return any data for $scope.Item

3) The last debugger reach $http call which return the data correctly as I observed in the console. But it never reach the controller side afterwards so no data is being displayed in the mobile app

I read about the natural behavior of angular async call so this seems to be normal. But in my case, what should I do to ensure that the data could reach the controller?

Many thanks

2 Answers 2

0

To achieve that without loosing performance, you should use $q.all(), so it will keep your request async and it will return the data once all the promises are resolved. Don't try a synchronic approach because that will reduce your performance. You can use it like this:

Your factory:

app.factory('GetDataList', function($q, $http) {
  var promises = [];
  var arrDataList = [];
  var requests = [{
    url: 'https://localhost/search',
    postData: {
      "param": "1"
    }
  }, {
    url: 'https://localhost/locate',
    postData: {
      "param": "2"
    }
  }];

  angular.forEach(requests, function(req) {
    executeRequest(req);
  })

  function resolveData(data) {
    debugger
    if (arrDataList.length === 0) {
      arrDataList = data.data;
    } else {
      arrDataList = arrDataList.concat(data.data);
    }
  }

  function executeRequest(req) {
    var promise = $http({
        url: req.url,
        method: 'GET',
        data: req.postData
      })
      .then(resolveData);

    promises.push(promise)
  }

  return {
    getAPIData: function() {
      debugger
      return $q.all(promises).then(function() {
        return arrDataList
      });
    }
  }

});

And your controller:

  $scope.GetList = function() {
    debugger
    GetDataList.getAPIData().then(function(item) {
      $scope.item = item
    });

    $scope.$broadcast('scroll.infiniteScrollComplete');
  }

What we are doing here is executing each request inside the requests array (using its url and postData) asynchronously and saving the promises inside an array. When getApiData is called, it returns a function that will be called after $q.all(promises), that means it will return the data after all those promises are finished (the promises ask if the arrDataList is empty and concats the new data if it's not).

This way you get to keep your async calls! And inside the controller you receive a promise instead of the data itself.

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

1 Comment

Excellent idea. Thanks for the explanation and the code sample. Really save my day
0

You should make it to be synchronized as in the below

var app = angular.module('plunker', []);

app.controller('MainCtrl', function($scope,serviceDemo) {
  $scope.name = 'World';

});
app.factory('serviceDemo', function ($http) {
    var arrDataList = [];
    var postData1 = []; var postData2 =[]

    var firstMethod=function(){ 
                $http({ 
                    method: 'GET',
                    url: 'a.json'
                }) 
                .then(function (response) {
                  console.log(response);
                    postData1=response.data;
                    arrDataList.push(postData1);
            //      console.log(postData1);
                secondMethod();     //put the second method call here
                });
    }
    var secondMethod=function(){
                $http({
                    method: 'GET',
                  url: 'b.json' 
                })
                   .then(function (response) {
                   postData2=response.data;
                arrDataList.push(postData2);
                   console.log(arrDataList);
                   });
     }
     var getAPIData= function () {
                firstMethod();

                return arrDataList;
     }

    return {
            getAPIData: getAPIData
    };
    });

Modification Made:

You need to call the second method inside the success block of your first method. By this way your first method gets executed, when the result is fetched your second method gets executed and then only control will come out of the first method block.

LIVE DEMO

1 Comment

I think he is trying to do it asynchronously, so it would be better to use a $q.all approach instead of chaining the promises.

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.