Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Promises With Google Maps Geocoder API

Im trying to create a set of functions that translates a set of addresses to lat long values using the Google Maps Geocoder API.

Currently, I have it successfully translating the addresses to lat long values but the function fully executes before theyre returned. I know this because it throws undefined errors before it logs the proper lat long values after.

I heard that javascripts promises can be a solution to this type of problem so I did a little bit of research but it doesn't seem to be helping the issues. Im new to promises so excuse me if Im going about this in the wrong way.

Here`s the relevant code

 function getPoints(geocoder,map) {
       let locationData = [];
       let latValue;
       for(let i = 0; i < addressData.length; i++){
            let getLatLong = new Promise(function(resolve,reject){
                 latValue = findLatLang(addressData[i].location, geocoder, map);
                 if(latValue!=undefined){
                      resolve(latValue());
                 } else {
                      reject();
                 }
            });
            getLatLong.then(function(){
                 console.log(latValue);
                 //returns a GMap latLng Object.
                 locationData.push( new google.maps.LatLng(latValue[0],latValue[1]));
            })
       }
       return locationData;
  }

function findLatLang(address, geocoder, mainMap) {
       geocoder.geocode({'address': address}, function(results, status) {
            if (status === 'OK') {
                 console.log(results);
                 return [results[0].geometry.location.lat , results[0].geometry.location.lng];
            } else {
                 alert('Couldnt\'t find the location ' + address);
                 return;
            }
       })
  }

Thanks in advance for any help or pointers you would have!

like image 487
MykalCodes Avatar asked Sep 05 '17 22:09

MykalCodes


People also ask

Is Google reverse geocoding API free?

The Geocoding API uses a pay-as-you-go pricing model. Geocoding API requests generate calls to one of two SKUs depending on the type of request: basic or advanced. Along with the overall Google Terms of Use, there are usage limits specific to the Geocoding API.

Can you geocode with Google Maps?

Geocoding API is one of the many services that Google Maps API eco-system offers. Geocoding is a process of converting a human readable physical address into geographic coordinates (latitude and longitude values).

How do I get the geocoding API key from Google Maps?

Go to the Google Maps Platform > Credentials page. On the Credentials page, click Create credentials > API key. The API key created dialog displays your newly created API key. Click Close.


1 Answers

Your main issue is that geocoder.geocode() is asynchronous and takes a callback. You are passing a function to the callback but treating the return value as if it will return from the main function, findLatLang(), but it won't. Currently findLatLang() returns nothing.

findLatLang() is where you should have the promise and return it from the function:

function findLatLang(address, geocoder, mainMap) {
    return new Promise(function(resolve, reject) {
        geocoder.geocode({'address': address}, function(results, status) {
            if (status === 'OK') {
                console.log(results);
                resolve([results[0].geometry.location.lat(), results[0].geometry.location.lng()]);
            } else {
                reject(new Error('Couldnt\'t find the location ' + address));
            }
    })
    })
} 

Then in the loop in getPoints() you can just collect those promises into an array and call Promise.all() on the array which will give you the values once all promises have resolved:

function getPoints(geocoder,map) {
    let locationData = [];
    let latValue;
    for(let i = 0; i < addressData.length; i++){
        locationData.push(findLatLang(addressData[i].location, geocoder, map))
    }
    return locationData // array of promises
}

var locations = getPoints(geocoder,map)

Promise.all(locations)     
.then(function(returnVals){
        // you should have return values here when
        // all promises have rsolved
          console.log(returnVals);
})

It's not clear where addressData is coming from - you are using it in the function, but it's not being passed in anywhere.

proof of concept fiddle

code snippet:

var geocoder;
var map;
var addressData = [{
  location: "New York, NY, USA"
}, {
  location: "Newark, NJ, USA"
}];

function initialize() {
  var map = new google.maps.Map(
    document.getElementById("map_canvas"), {
      center: new google.maps.LatLng(37.4419, -122.1419),
      zoom: 13,
      mapTypeId: google.maps.MapTypeId.ROADMAP
    });
  var coordinates = [{}];
  var geocoder = new google.maps.Geocoder();
  var bounds = new google.maps.LatLngBounds();

  function findLatLang(address, geocoder, mainMap) {
    return new Promise(function(resolve, reject) {
      geocoder.geocode({
        'address': address
      }, function(results, status) {
        if (status === 'OK') {
          console.log(results);
          resolve([results[0].geometry.location.lat(), results[0].geometry.location.lng()]);
        } else {
          reject(new Error('Couldnt\'t find the location ' + address));
        }
      })
    })
  }

  function getPoints(geocoder, map) {
    let locationData = [];
    let latValue;
    for (let i = 0; i < addressData.length; i++) {
      locationData.push(findLatLang(addressData[i].location, geocoder, map))
    }
    return locationData // array of promises
  }

  var locations = getPoints(geocoder, map)

  Promise.all(locations)
    .then(function(returnVals) {
      // you should have return values here when
      // all promises have rsolved
      console.log(returnVals);
      coordinates = returnVals;
      returnVals.forEach(function(latLng) {
        console.log(latLng);
        var marker = new google.maps.Marker({
          position: {
            lat: latLng[0],
            lng: latLng[1]
          },
          map: map
        });
        bounds.extend(marker.getPosition());
        map.fitBounds(bounds);
      })
    })
}
google.maps.event.addDomListener(window, "load", initialize);
html,
body,
#map_canvas {
  height: 100%;
  width: 100%;
  margin: 0px;
  padding: 0px
}
<script src="https://maps.googleapis.com/maps/api/js"></script>
<div id="map_canvas"></div>
like image 181
Mark Avatar answered Sep 29 '22 05:09

Mark