purencool
purencool

Reputation: 423

Can't get $http response data to controller

I have a factory that returns a JSON object using angular. $http.get request is getting data because I can see it in console.log(data). I also know if I hard code the JSON object into the factory the controller receives the data and displays in the view correctly

My questions is this why is list: function(callback) not returning the data to my controller even though $http.get is getting it?

  .factory('countries', function($http){
          return {
            list:  function(callback){
        $http.get('../test.json').success(function(data, status, headers) {

            console.log("success");
            console.log(data);
            //console.log(status);
        }).error(function(data, status) {

            //console.log("error");
            // console.log(data);
            // console.log(status);
        });
      }
    };

    /*
    var x = {
        list: [
                {
                    "name": "China",
                    "population": 1359821000,
                    "flagURL": "//upload.wikimedia.org/wikipedia/commons/f/fa/Flag_of_the_People%27s_Republic_of_China.svg",
                    "capital": "Beijing",
                    "gdp": 12261
                },
                {
                    "name": "India",
                    "population": 1205625000,
                    "flagURL": "//upload.wikimedia.org/wikipedia/en/4/41/Flag_of_India.svg",
                    "capital": "New Delhi",
                    "gdp": 4716
                },
                {
                    "name": "United States of America",
                    "population": 312247000,
                    "flagURL": "//upload.wikimedia.org/wikipedia/en/a/a4/Flag_of_the_United_States.svg",
                    "capital": "Washington, D.C.",
                    "gdp": 16244
                }
            ]
        };

      console.log(x);
      return x;
     */

     })

     .controller('View2Ctrl', function ($scope, countries){
      $scope.countries = countries.list;
      });

Upvotes: 1

Views: 4066

Answers (4)

Michael Kang
Michael Kang

Reputation: 52837

You probably want something like this:

.factory('countries', function($http){
      var list = [];
      $http.get('../test.json').success(function(data, status, headers) {
          angular.copy(data, list);
      })

      return {
        list: list
      }
};

Then you can bind to the list like this:

.controller('View2Ctrl', function ($scope, countries){
     $scope.countries = countries.list;
});

An alternative, equally valid approach is this:

.factory('countries', function($http){
      return {
        list: function() { return $http.get('../test.json'); }
      }
};

Then in your controller:

.controller('View2Ctrl', function ($scope, countries){
     $scope.countries = [];
     countries.list().success(function(data) {
         $scope.countries = data;
     });
});

Remember that $http.get('../test.json') is already a promise, which is why you can return it without any unnecessary promise/resolve handling.

Upvotes: 2

Hristo Enev
Hristo Enev

Reputation: 2541

First of all it is better to use then and catch instead of success and error. That way you are getting the advantage of the $http promise.

Second of all you need to return the data in your list function like so:

$http.get('../test.json')
  .then(function(response) {
    return response;
  })
  .catch(function(response) {
    console.log(response);
  });

Then in your controller you just need to call the function:

$scope.countries = countries.list();

That's it.

BONUS: How I do it.

In my factory I have fetch set and get functions and an array variable for the data.

.factory('countries', function($http) {
    var service = {
        fetch: fetch,
        get: get
    };

    var countries = [];

    return service;

    function fetch() {
        $http.get('../test.json')
            .then(set)
            .catch(function(err) {
                console.log(err);
            });
    }

    function set(data) {
        countries = data;
    }

    function get() {
        return countries;
    }
});

When loading your controller you can call the fetch function to get all the countries and if you pass the get function to the controller you can call it whenever you like to get those countries you fetched already. That way you won't make additional requests for countries when you don't need them. You also get the advantage of the factory that makes a singleton. This way this data(countries) are shared across every controller where you inject countries until you remove or change the data from the factory (or refresh the page).

.controller('View2Ctrl', function ($scope, countries){
    countries.fetch();
    $scope.getCountries = countries.get;
});

Now in your view you can just call the get function to get the countries.

<div ng-repeat="country in getCountries()"></div>

Upvotes: 1

Aniket Sinha
Aniket Sinha

Reputation: 6031

Because you are not returning anything from your $http request. Change your code to:

  .factory('countries', function($http, $q){
      return {
        list:  function(callback){
            var d = $q.defer();        
            $http.get('../test.json').success(function(data, status, headers) {

               console.log("success");
               console.log(data);
               //console.log(status);
               d.resolve(data);
            }).error(function(data, status) {

            //console.log("error");
            // console.log(data);
            // console.log(status);
               d.reject(data);
            });
            return d.promise;
  }
};

Upvotes: 2

vanhonit
vanhonit

Reputation: 617

I think you should call change to $scope.countries = countries.list(); to run send request to server.

Upvotes: 0

Related Questions