0

I seem to be stuck while trying to modify a global variable from within an Angular.forEach loop.

I can modify the variable fine, but I can't seem to get that change to apply to the variable when accessed outside of the loop.

I've tried a variety of 'var self = this' and using 'this.addresses = []' throughout the loop to access the array, but that resulted in the same problem. By the time I get to my 'return' statement, my changes are lost.

Here's the code:

$scope.getLocation = function(val) {
var geocoderRequest = {
    address: String(val),
    componentRestrictions: {
        'country': 'US'
    }
};
var addresses = [1]; // **** shows addresses as [1] *****
geocoder.geocode(geocoderRequest, function(callbackResult) {
    console.log('address in geocode: ' + addresses); // ***** shows addresses as [1] ****
    var f = '';
    angular.forEach(callbackResult.results, function(item) {
        console.log('address in angular: ' + addresses); // **** shows addresses as [1] *****
        if (item.types[0] == 'locality') {
            for (f = 1; f < item.address_components.length; f++) {
                if (item.address_components[f].types[0] ==
                    "administrative_area_level_1") {
                    addresses.push(item.address_components[0].short_name + ', ' + item.address_components[
                        f].short_name);
                    console.log('addresses in each: ' + addresses); // **** shows addresses as [1, 2, 3] after I 'push' 2 and 3 into addresses array ****
                    break;
                }
            }
        }
    });
});
console.log('addresses outside: ' + addresses); // ***** shows addresses as [1] even after pushing 2 and 3 *****
return addresses;

};

Nurdin
  • 23,382
  • 43
  • 130
  • 308
James Gentes
  • 7,528
  • 7
  • 44
  • 64
  • 2
    You need to do all of your work with the results of the AJAX call inside of the callback function. See [this question](http://stackoverflow.com/q/14220321/497356) for details. – Andrew Whitaker Sep 24 '14 at 00:35
  • There are so many similar questions on SO, check [this](http://stackoverflow.com/questions/14220321/how-to-return-the-response-from-an-ajax-call) and [this](http://stackoverflow.com/questions/6847697/how-to-return-value-from-an-asynchronous-callback-function) – PSL Sep 24 '14 at 00:35
  • See https://docs.angularjs.org/api/ng/service/$q – Phil Sep 24 '14 at 01:04
  • Thanks @Phil, I didn't know about the $q service in Angular. That did the trick. – James Gentes Sep 24 '14 at 23:24

1 Answers1

1

The final solution was to use Angular's $q to return a promise:

In the controller:

.controller('LaunchformController', 
['$scope', '$q', 'geocoder', function ($scope, $q, geocoder) {

  $scope.getLocation = function(val) {      
    var deferred = $q.defer();      

    geocoder.geocode({ address: String(val), componentRestrictions: {'country':'US'} }, 
      function(callbackResult) {        
        deferred.resolve(callbackResult);
    });

    return deferred.promise;            
  };
}])

In the service:

.service('geocoder',function() {
    this.geocode=function(georequest, outerCallback) {
      var geocoder = new google.maps.Geocoder();
      geocoder.geocode( georequest, function(results, status) {        
        if (status == google.maps.GeocoderStatus.OK) {          
          var f = '';                  
          var addresses = [];
          angular.forEach(results, function(item){  
            if (item.types[0] == 'locality') {          
              for (f=1;f<item.address_components.length;f++) {              
                if (item.address_components[f].types[0] == "administrative_area_level_1") {
                addresses.push(item.address_components[0].short_name + ', ' + item.address_components[f].short_name);            
                break;
                }
              }
            }            
          });
          outerCallback(addresses);         
        } else {
          outerCallback({success:false, err: new Error('Geocode was not successful for the following reason: ' + status), results: null});
        }
      });
    };
  })
James Gentes
  • 7,528
  • 7
  • 44
  • 64