Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Google geocoding multiple addresses in a loop with javascript, how do I know when everything is done?

I've got a form that asks for a list of locations (not a lot, normally only 3 or 4 but that number is dynamic). When the form is submitted, I have to parse the data, use Google geocoding to get the locations, and then draw a line connecting the points in order. I have the parsing working, but I'm stuck on the geocoding part, mostly because of the asynchronous nature of it. Assume my address strings are stored in the array 'addresses', this is how far I've gotten:

function someFunction(addresses) {
  var coords = [];
  for(var i = 0; i < addresses.length; i++) {
    currAddress = addresses[i];
    var geocoder = new google.maps.Geocoder();
    if (geocoder) {
      geocoder.geocode({'address':currAddress}, function (results, status)
        if (status == google.maps.GeocoderStatus.OK) {
          coords.push(results[0].geometry.location);
        } 
        else {
          throw('No results found: ' + status);
        }
      });
    }
  }
  // Initially I tried to work with the data here, but it wasn't all present yet.
}

Drawing the line is easy enough, I've done that before when users provided geographic lat/lng coordinates. My problem is, because the coordinates are only added in the callback, how do I know when it's done? I can't just dump that into a function and put in the callback because I need to wait until all the coordinates have been processed.

I also read about someone who had issues with results not coming back in order but I didn't understand the provided response. If someone has an answer that can help me with my specific issue and ensure the results come back in order, I would greatly appreciate.

NB: I hand-bombed that code, so there may be typos. My actual code thus far "works", I just don't know who to move from what I have to doing something once all addresses are processed. Also, this is currently being developed as an internal application for testing. Once testing is finished, it will comply fully with Google's TOS. This means I don't have a page I can link to. The entire application is also over 2,000 lines of code and contains some proprietary company information at this moment which will eventually be phased out, so pasting the entire thing or sending it out isn't feasible. I hope that doesn't pose too big a problem.

like image 731
user985219 Avatar asked Jan 29 '12 10:01

user985219


People also ask

How do you test geocoding?

Geocoding request and response (latitude/longitude lookup) You can test this by entering the URL into your web browser (be sure to replace YOUR_API_KEY with your actual API key). The response includes the latitude and longitude of the address.

What happens when you exceed the Google geocoding API rate limit?

Google Maps Geocoding Rate Limit According to Google's API Usage and Billing page, there is a limit of 50 requests per second. If you exceed this amount, subsequent requests to the API will fail with the OVER_DAILY_LIMIT or OVER_QUERY_LIMIT status code and the geocoded data will not be returned.

How long does it take to geocode addresses?

When address information is imported, it can take up to 48 hours to complete the geocoding process, depending on the number of addresses in the import. Mapping status can be found at Settings > Database > Mapping status. Here you can see how many people are in your nation and whether or not these profiles are mailable.

How accurate is Google geocoding?

Results. Respectively 81.4% and 84.4% of addresses were geocoded to the exact address (65.1% and 61.4%) or to the street segment (16.3% and 23.0%) with methods A and B.


3 Answers

function someFunction(addresses, callback) {
    var coords = [];
    for(var i = 0; i < addresses.length; i++) {
        currAddress = addresses[i];
        var geocoder = new google.maps.Geocoder();
        if (geocoder) {
            geocoder.geocode({'address':currAddress}, function (results, status) {
                if (status == google.maps.GeocoderStatus.OK) {
                    coords.push(results[0].geometry.location);
                    if(coords.length == addresses.length) {
                        if( typeof callback == 'function' ) {
                            callback();
                        }
                    }
                } 
                else {
                    throw('No results found: ' + status);
                }
            });
        }
     }
  }
}

//Usage
someFunction(addresses, function() {
    // Do something after getting done with Geocoding of multiple addresses
});

Use of Callback function is amazing

like image 118
jwchang Avatar answered Oct 19 '22 20:10

jwchang


You could check if all calls have been finished by comparing the number of results to the number of addresses:

function someFunction(addresses) {
    var currAddress, coords = [];
    for (var i = 0; i < addresses.length; i++) {
        currAddress = addresses[i];
        var geocoder = new google.maps.Geocoder();
        if (geocoder) {
            geocoder.geocode({'address':currAddress}, function(results, status) {
                if (status == google.maps.GeocoderStatus.OK) {
                    coords.push(results[0].geometry.location);

                    // Check if all calls have been processed
                    if (coords.length == addresses.length) {
                        someOtherFunction(coords);
                    }
                }
                ...
            });
        }
    }
}

function someOtherFunction(coords) {
    // Geocoding has been done for all addresses
    ...
}
like image 32
Julian D. Avatar answered Oct 19 '22 20:10

Julian D.


If you are utilizing libraries such as jQuery, you could take advantage of Deferred Object to perform a chainable requests via geocoder.geocode function.

Example

function initMap() {
   
    var geocoder = new google.maps.Geocoder();

    var addreses = [
    { "lat": 60.173890, "lng": 24.941025 },
    { "lat": 60.461608, "lng": 22.266598 },
    { "lat": 61.498714, "lng": 23.760940 }
    ];

    var deferreds = getGeocodeAddressDeferred(geocoder,addreses);
    $.when.apply($, deferreds).done(function (locations) {

        //print results
        $.each(arguments, function (i, data) {
            $("div#result").append(data + "<br/>");
        });
    });
}
function getGeocodeAddressDeferred(geocoder, addreses) {
    var deferreds = [];
    
    $.each(addreses, function (i,address) {
        deferreds.push(geocodeAddress(geocoder, address));
    });

    return deferreds;
}

function geocodeAddress(geocoder, latLng) {
    var deferred = $.Deferred();
    geocoder.geocode({ 'location': latLng }, function (results, status) {
        if (status === google.maps.GeocoderStatus.OK) {
            deferred.resolve(results[0].formatted_address);
        } 
    });
    return deferred.promise();
}
 <script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.3/jquery.min.js"></script>
    <script src="https://maps.googleapis.com/maps/api/js?callback=initMap"
            async defer></script>
<div id="result"/>
like image 1
Vadim Gremyachev Avatar answered Oct 19 '22 20:10

Vadim Gremyachev