Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

AngularJS: Waiting for an asynchronous call

I can't wrap my head around AngularJS' concept of promises.

I have a provider:

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

packingProvider.provider('packingProvider',function(){
    return{
       $get: function($http){
           return{
              getPackings: function(){
                  $http.post('../sys/core/fetchPacking.php').then(function(promise){
                      var packings = promise.data;
                      return packings;
                  });
              }
           }
       }
   }
});

As you can see, this provides a method getPackings(), which will return an object

Now, if I use that in my main application to receive the data, the call will be asynchronous, resulting in an issue where I would have to 'wait' for the data:

var packings = packingProvider.getPackings();

console.log(packings); // undefined

How would i do this without refactoring the process into my main controller?

like image 554
user2422960 Avatar asked Oct 08 '13 14:10

user2422960


2 Answers

The return value from within your then method isn't returning when you think it is; it's returning later.

In the statement var packings = packingProvider.getPackings(); the return value is undefined because the promise returned from $http is asynchronous. That means that the call to $http.post happens, does not complete, then your function returns. In JS functions that don't return anything return undefined. The post call completes later and executes return packings; which gets returned to nowhere.

The getPackings method should probably return the promise from $http.post directly. That way any code that wants to use this method can call then on the promise directly and set the value the way it needs to. In a controller you could assign that promise directly to the $scope and use it in your view. Here's a nice post that explains that particular feature: http://markdalgleish.com/2013/06/using-promises-in-angularjs-views/

Incidentally, it looks like you've got a long-winded service declaration there; any reason not to shorten it to something like this?

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

module.service('packing', function($http) {
  return {
    getPackings: function() {
      return $http.post('../sys/core/fetchPacking.php');
    }
  };
});

I'm relatively new to AngularJS but I don't see any gain in all that typing. ( =

like image 122
drhayes Avatar answered Sep 21 '22 12:09

drhayes


Try

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

packingProvider.provider('packingProvider',function(){
    return{
       $get: function($http){
           return{
              getPackings: function(){
                  return $http.post('../sys/core/fetchPacking.php').then(function(response){
                      return response.data; // packings
                  });
              }
           }
       }
   }
});

Then

packingProvider.getPackings().then(function(packings){
    console.log(packings);
});

Main idea: you need to return the promise object from the getPackings function. Not sure if you can make the call to it synchronous but it's almost definitely not a great idea to do so. Also, if you want to make "packings" a model object on your controller and use for a two-directional binding, you can safely assign the promise object, which Angular will resolve as soon as data comes through:

$scope.packings = packingProvider.getPackings();

UPDATE

As of 1.2.0-rc.3 promise unwrapping has been deprecated (https://github.com/angular/angular.js/blob/master/CHANGELOG.md#120-rc3-ferocious-twitch-2013-10-14) , so the line of code above will not result in a two-directional binding any more.

like image 33
Konstantin K Avatar answered Sep 21 '22 12:09

Konstantin K