0

I'm trying to grab a list of countries from a GitHub repo on the fly without storing all of the information in JS or in my own API, so I wrote a one-off service to take care of this for me and cache the results in the browser in case they're needed again. However, I've noticed that the way I've written it, the $http.get is called on load rather than upon service injection into the controller--meaning that the browser is requesting all of this country data even when it's not needed (e.g., even when a user visits the country page.

The way I've structured this, because the service simply returns a promise, I can just call countrylist.then(...) in the controller. Is there a way to keep that but still delay the request to Github until it's actually needed?

Code below:

angular.module('myModule')
    .factory('countrylist', ['$http', 'growl', '$q', function ($http, growl, $q) {

        var deferred = $q.defer();
        var flagUrl = "https://raw.githubusercontent.com/hjnilsson/country-flags/master/png250px/{}.png";

        $http.get('https://raw.githubusercontent.com/lukes/ISO-3166-Countries-with-Regional-Codes/master/slim-2/slim-2.json',
                {cache: true})
                .success(function (data) {
                    angular.forEach(data, function (item) {
                        item.flag = flagUrl.replace("{}", item['alpha-2'].toLowerCase());
                    });

                    deferred.resolve(data);
                }).error(function (data) {
                    growl.warn("Error loading country data");
                    deferred.reject();
                });

        return deferred.promise;

    }]);

2 Answers 2

1

Everything in the factory is run as soon as the factory is injected once into any controller, which happens when your app is bootstrapped.

The only way to do this is to return an object from your factory with a method that fetches the data.

angular.module('myModule')
.factory('countrylist', ['$http', 'growl', '$q', function ($http, growl, $q) {
  return {
    fetch: function() {
      var deferred = $q.defer();
      var flagUrl = "https://raw.githubusercontent.com/hjnilsson/country-flags/master/png250px/{}.png";

      $http.get('https://raw.githubusercontent.com/lukes/ISO-3166-Countries-with-Regional-Codes/master/slim-2/slim-2.json',
            {cache: true})
            .success(function (data) {
                angular.forEach(data, function (item) {
                    item.flag = flagUrl.replace("{}", item['alpha-2'].toLowerCase());
                });

                deferred.resolve(data);
            }).error(function (data) {
                growl.warn("Error loading country data");
                deferred.reject();
            });

      return deferred.promise;
    }
  };
}]);

And then in your controller you would obviously have to do

countryList.fetch().then(...)
Sign up to request clarification or add additional context in comments.

Comments

1

Let it be simple. It's as simple as

  1. Return promise in your service(no need to use then in service)
  2. Use then in your controller

Demo. http://plnkr.co/edit/cbdG5p?p=preview

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

app.service('myService', function($http) {
  return {
    async: function() {
      return $http.get('test.json');  //1. this returns promise
    }
  };
});

app.controller('MainCtrl', function( myService,$scope) {
  myService.async().then(function(d) { //2. so you can use .then()
    $scope.data = d;
  });
});

This is my copy/pasted answer from Processing $http response in service

Comments

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.