snaggs
snaggs

Reputation: 5713

Bootstrap typeahead doesnt work when call async task from service in angularJS

I try to play with bootstrap typeahead and angular. When current method was in controller - all worked fine:

$scope.getLocation_work = function(val) {
    return $http.get('http://maps.googleapis.com/maps/api/geocode/json', {
      params: {
        address: val,
        sensor: false
      }
    }).then(function(res){
      var addresses = [];
      angular.forEach(res.data.results, function(item){
        addresses.push(item.formatted_address);
      });
      return addresses;
    });
  };

When I tried to put the logic into service, I started get errors:

ypeError: Cannot read property 'length' of undefined

in controller

$scope.getLocation = function(val) {
            UtilsFactory.getLocation(val).then(function(res){
                var addresses = [];
                angular.forEach(res, function(item){
                    addresses.push(item.formatted_address);
                });
                return addresses;
            });
        };

Service

app.factory('UtilsFactory', ['$http', '$q', function($http, $q) {
                return {
                    getLocation : function(val) {
                          var deferred = $q.defer();
                          var response = $http.get('http://maps.googleapis.com/maps/api/geocode/json', {
                params: {
                    address: val,
                    sensor: false
                }
            });

             deferred.resolve(response);
               return deferred.promise;
                }      
       }
  }
]);

Do I miss something?

Here is Demo in Plunker

Thanks,

Upvotes: 0

Views: 2073

Answers (1)

pkozlowski.opensource
pkozlowski.opensource

Reputation: 117370

There were 2 problems in your plunker:

(1) For whatever reason you were writing $http promise callback differently when called from a controller and differently when a promised was returned from the service. But promise hitting a backend is the same promise with the same results so it should be handled the same:

        $scope.getLocation = function(val) {
            return UtilsFactory.getLocation(val).then(function(res){
                var addresses = [];
                angular.forEach(res.data.results, function(item){
                    addresses.push(item.formatted_address);
                });
                return addresses;
            });
        };

On top of this you were missing the return in the $scope.getLocation function!

(2) $http already works with promises so there is no need to use $q on top of it. You can write your service as simply as:

app.factory('UtilsFactory', ['$http', function($http) {
  return {
    getLocation : function(val) {
        return $http.get('http://maps.googleapis.com/maps/api/geocode/json', {
          params: {
            address: val,
            sensor: false
          }
        });
    }
  };
}]);

Finally a fixed plunk: http://plnkr.co/edit/hG5iHWfGq3QNAp6J8YSW?p=preview

Upvotes: 1

Related Questions