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 ?

3 Answers 3

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

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

2 Comments

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
@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.
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.

Comments

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:

2 Comments

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 ?
@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.

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.