2

I have a factory which provides me a promise when getting a json file :

myapp.factory('topAuthorsFactory', function($http, $q) {
    var factory = {
        topAuthorsList: false,
        getList: function() {
            var deffered = $q.defer();
            $http.get('../../data/top_10_authors.json')
                .success(function(data, status) {
                    factory.topAuthorsList = data;
                }).error(function(data, status) {
                    deffered.reject('There was an error getting data');
                });
            return deffered.promise;
        }
    };
    return factory;
});

and in my controller I want to display the content of the json file on my console as the following :

myapp.controller('topAuthorsController', function($scope, topAuthorsFactory) {


  $scope.listAuthors = topAuthorsFactory.getList().then(function(topAuthorsList) {

      $scope.listAuthors = topAuthorsList;
      console.log('Testing...');

  }, function(msg) {
    alert(msg);
  });

  console.log($scope.listAuthors);
    }

but in my console I'm getting this :

enter image description here

so how can I solve this ? and why I dont see the message "testing..." in console ?

Renaud is Not Bill Gates
  • 1,684
  • 34
  • 105
  • 191

3 Answers3

5

You should resolve promise when you received response.

deferred.resolve(data)

Ideally you shouldn't follow the approach by which you are doing, creating new promise is considered as anti-pattern while you are dealing with $http.get which already return promise itself, you could utilize that promise. So basically you need to clean up your factory. By returning the $http.get object & .then function over it, (also .success & .error methods are deprecated). 1st function of then will get call when data received & otherwise the error function will get call. Basically for resolving or rejection promise you need to return data from promise, which will call subsequent .then function of caller method.

Factory

myapp.factory('topAuthorsFactory', function($http) {
  var factory = {
    topAuthorsList: false,
    getList: function() {
      //returning promise
      return $http.get('../../data/top_10_authors.json')
        .then(function(response) {
           var data = response.data;
           factory.topAuthorsList = data;
           //returning data to resolving promise
           return data;
        }, function(error) {
            return 'There was an error getting data';
        });
    }
  };
  return factory;
});

Edit

Basically you have assigned factory method call topAuthorsFactory.getList() to $scope.listAuthors method which is not required here, and then you are printing $scope.listAuthors variable which will obviously have promise object. So you should remove that assignment, & $scope.listAuthors value will be assigned from the .then function.

Controller

//remove $scope.listAuthors assignment which is incorrect.
topAuthorsFactory.getList().then(function(topAuthorsList) {
   $scope.listAuthors = topAuthorsList;
   console.log('Testing...');

}, function(msg) {
    alert(msg);
});

its asynchronous which will evaluate its function when async call get completed..the console.log statement

Pankaj Parkar
  • 134,766
  • 23
  • 234
  • 299
  • Thank you for your help I changed my factory to use the promise which is returns by the get method as you said, but I console I'm still getting that Promise object and I want to get the content of the json file printed in the console – Renaud is Not Bill Gates Dec 12 '15 at 20:02
  • @AimadMAJDOU see you are confused with async call & how it works.. you could not get value of `$scope.listAuthors` before ajax gets completed..you need to place that `console.log` factory method call `.then` function..also need to remove unneccessary assignment while calling `topAuthorsFactory.getList()` method..Look at the updated answer for more detailed version. – Pankaj Parkar Dec 12 '15 at 20:05
1

Try this:

.success(function(data, status) {
    factory.topAuthorsList = data;
    deffered.resolve(data);
}).error(function(data, status) {
    deffered.reject('There was an error getting data');
});

You have to resolve the promise to get the data.

Jeremy Jackson
  • 2,247
  • 15
  • 24
1

The first problem is that you log the promise itself immediately, and not it's resolution value. The second is that you don't even resolve the returned promise in getList. Try this instead:

getList: function() {
    return $http.get('../../data/top_10_authors.json').then(function(response) {
        return response.data;
    }, function() {
        throw 'There was an error getting data';
    });
}

// ...

$scope.listAuthors = null;
topAuthorsFactory.getList().then(function(topAuthorsList) {
    $scope.listAuthors = topAuthorsList;
    console.log('Testing...');
    console.log($scope.listAuthors);
}, function(msg) {
    alert(msg);
});

I noticed you used the explicit promise construction antipattern when using $http. $http already returns a promise, and that is favoured over success and error callbacks. I improved your getList function to employ promise chaining.

You can find some tutorial on using promises:

Community
  • 1
  • 1
Tamas Hegedus
  • 28,755
  • 12
  • 63
  • 97
  • Thanks for you answer I did as you said and I worked with the `promise ` from the `$http.get` function, but in console I get `Null`, from which I understand that the code inside the `then` method didn't change the `$scope.listAuthors` variable _(I tried to log the `topAuthorsList` variable inside the `then` function and I got the json file printed on the console)_ how can I solve this ? – Renaud is Not Bill Gates Dec 12 '15 at 20:13
  • @AimadMAJDOU The callback function in `then` is called when the promise resolves. That always happens later than the promise creation. You have to wait for the callback and use the value in the callback function. That's how promises work. Promise means that a value will be available later inside a callback. – Tamas Hegedus Dec 12 '15 at 20:18