Google Maps API Geocode Synchronously - google-maps

I was wondering if its possible to geocode something using googlemaps api synchronously so instead of waiting for a callback function to be called, it would wait for a value to be returned. Has anyone found a way to do something like this.
P.S.: I'm using version 3 of the api

Yes, what you are trying to achieve is possible, although a synchronous request is not needed.
Look at this code
function StoreGeo()
{
var address = $('input[name=zipcode]').val() + ', ' + $('input[name=city]').val();
geocoder.geocode( { 'address': address}, function(results, status) {
if (status == google.maps.GeocoderStatus.OK) {
var ll = results[0].geometry.location.toString();
llarr = ll.replace(/[\(\) ]/g, '').split(',');
for(i = 0; i < llarr.length;i++)
{
$('#form').append($('<input type="hidden" name="'+(i == 0 ? 'lat' : 'long')+'">').val(llarr[i]));
}
$('#form').submit();
}
else
{
alert(status);
}
});
$('#form').unbind('submit');
return false;
}
$(document).ready(function () {
//init maps
geocoder = new google.maps.Geocoder();
$('#form').bind('submit',function() {
StoreGeo();
});
});
So, attach submit handler to the form, when it is submitted do the geo request based on the address info from your form. But at the same time postpone submitting by returning false in the handler.
The response handler will make 2 hidden textfields 'lat' and 'long' and store the response. finally the form is submitted by client script, including the two new fields. At the server side you can store them in the DB.
!! Note that this is possible, but is probably against the google terms, like noted above.

The Geocoder calls your callback function with the value. That's the only way to do it. If it were synchronous, your script would freeze while it waited for the Geocode to process. There really isn't any reason to do it like that.
What exactly are you trying to accomplish?

I simply use a flag during form submit to know when submit should pass or when it should wait for geocoding. When geocoding is done it will then re-submit the form again.
var hasGeocoded = false;
searchFrom.on('submit', function(){
//If not geocoded yet
if (!hasGeocoded) {
var geocoder = new google.maps.Geocoder();
var location = locationEl.val();
geocoder.geocode({'address': location}, function (results, status) {
hasGeocoded = true;
if (status == google.maps.GeocoderStatus.OK) {
$('#coords').val(
results[0].geometry.location.lat() + ',' + results[0].geometry.location.lng()
);
}
searchFrom.submit();
});
return false; //wait for geocoder to finish and re-submit the form
}
return true;
});

Related

Address validation using Google Maps - Check Address

I'm letting users add an address to their posts using Google Maps.
If a user enters nothing for the map or enters odd special characters (#$!##) it crashes the website and gives me this error:
var lat = data.results[0].geometry.location.lat;
^
TypeError: Cannot read property 'results' of undefined
I'm trying to figure out a way to check for this error when the form is submitted. So far I have had zero luck. Is it possible to check for this error?
I've seen code like this but everything in undefined and I'm not sure how to define it in this case and frankly I'm not sure how the code below is operating.
if (status == google.maps.GeocoderStatus.OK) {
var lat = results[0].geometry.location.lat();
var lon = results[0].geometry.location.lng();
searchStores(lat, lon);
} else {
$addressErrorP.removeClass('hide');
}
Thanks for any help!
Figured it out: Simple and works perfectly.
Step 1: Make sure this is on your page.
<script type="text/javascript" src="https://maps.google.com/maps/api/js?sensor=false"></script>
Then
$('#checkingAddress').click(checkGeocode)
function checkGeocode() {
var addr = document.getElementById('location')
// Get geocoder instance
var geocoder = new google.maps.Geocoder()
// Geocode the address
geocoder.geocode({ address: addr.value }, function (results, status) {
if (status === google.maps.GeocoderStatus.OK && results.length > 0) {
alert('looks good')
// set it to the correct, formatted address if it's valid
addr.value = results[0].formatted_address
// show an error if it's not
} else alert('Invalid address')
})
}

Geocoding Service returns uncaught type error: #<Object> object has no method 'apply'

I'm trying to get lat long coordinates from an address using the Google maps api v3 in Wakanda Studio. I have submitted to the Wakanda forum as well. I searched the v3 documentation as well, which basically advises to pass a JSON object and a call back function to geocode, which is displayed in the code below.
The geocode call is also encapsulated in the codeAddress function. When I run the code, I can see the Geocoder JSON object results that include the lat long coordinates. However, I am getting a strange error message:
Uncaught Error Type: Object #<Object> has no method 'apply'
Any pointers would be appreciated, and let me know if you need to see screenshots/details of anything else emailed, since I cannot post screenshots on stack overflow yet.
button1.click = function button1_click (event)
{
$$('map').setCenter("London, England");
var address1 = "911 South Park Street, Kalamazoo, MI, 49001";
geocoder = new google.maps.Geocoder();
if(!geocoder) {
alert("no geocoder available");
} else {
alert("geocoder available");
}
codeAddress(address1);
};
function codeAddress(address) {
var address1 = address;
geocoder.geocode(
{'address': address1},
{onSuccess: function(results, status) {
if (status == google.maps.GeocoderStatus.OK) {
//setCenter to mid
//addMarker
var lat = results[0].geometry.location.lat;
var lon = results[0].geometry.location.lon;
alert(lat);
} else {
alert("geocoder issue " + status);
}
}
});
}
I also tried something similar in Wakanda, but it seems the browser is blocking the call due to CORS (cross-reference of domains), so I used the below approach.
Wakanda client --> Wakanda Server --> Google Maps API --> Back to Wakanda Server --> Back to Wakanda client
Client side code:
button1.click = function button1_click (event) {
var address = $$("addressField").getValue();
address = encodeURI(address);
// Make call to server
response = $sources.businesses.getGeoCoordinates(address);
address_info = JSON.parse(response);
if (address_info && address_info.status === "OK") {
$$("business_latitude_field").setValue(
address_info.results[0].geometry.location.lat
);
$$("business_longitude_field").setValue(
address_info.results[0].geometry.location.lng
);
alert('We got latitude & longitude of your address.');
} else {
alert("Could not find latitude and longitude of your given address.");
}
}
Server side code - Code of getGeoCoordinates public method in business data class
function (address) {
// Call google geocode service to convert given address into lat / long
if (address) {
var api_url = "http://maps.googleapis.com/maps/api/geocode/json?sensor=false&address=" + address;
xhr = new XMLHttpRequest();
xhr.open("GET", api_url);
xhr.send();
var response = xhr.responseText;
return response;
}
}
Hope it helps.

Asynchronous Call in Google Map

Ok, Here is my JS Function :
function GetLatLong() {
var geocoder = new google.maps.Geocoder();
var address = $('#txtAddress').val() + ', ' + $('#txtCity').val() + ', ' + $find('drpState').get_text() + ', ' + $find('drpCountry').get_text();
var result = false;
geocoder.geocode({ 'address': address }, function (results, status) {
if (status == google.maps.GeocoderStatus.OK) {
var location = results[0].geometry.location;
$('#hiddenLatLong').val(location);
result = true;
}
else {
alert("Geocode was not successful for the following reason: " + status);
result = true;
}
});
return result;
}
Now, what i want is, i want to return the result once i store the value in hidden field. Here what happens is, i am calling this function on button click, but as the call is asynchronous, it returns false on the click and i cannot get the resultant value in hidden field. Is there any way where i can wait or some work around with which it can be obtained in the hidden field?
The second parameter in the geocode function is a callback function that will be invoked if the geocode results return. So from your given code the hidden value should be set if Google returns a result.
However your GetLatLong() function is completed earlier and therefore returns false. So you should not make your processing dependent on this method return value.

How to extract latitude and longitude from Google Maps autocomplete

I'm building an web app that uses this code to search for addresses:
http://code.google.com/intl/en/apis/maps/documentation/javascript/examples/places-autocomplete.html
Type there, New York, NY.
So, when the map is loaded in the DOM after the user using the autocomplete option, the user can save the Location Address in the database, and it will be available as it is "ex. New York, NY". But, for the application I need to save also the Latitude and Longitude.
But I have no ideia how to grab them from the Google API.
As a test app, I'm still using the google code.
I guess I should create some HIDDEN fields and assign the latitude and longitude to them as the user chooses the Address.
Any implementation for my problem is welcome!!
Thanks in advance
P.S:
As I'm new in StackOverflow I could't answer myself.
So I'm editing the post, as suggested by stackoverflow, and here is the solution based in Daniel's answer and some researches in the Google Api:
function getLatLng( address )
{
var geocoder = new google.maps.Geocoder();
geocoder.geocode( { 'address' : address }, function( results, status ) {
if ( status == google.maps.GeocoderStatus.OK ) {
var mapLatLng = document.getElementById( 'mapLatLng' ); // mapLatLng is my hidden field, use your own
mapLatLng.value = results[0].geometry.location.lat() + ', ' + results[0].geometry.location.lng();
} else {
alert( "Geocode was not successful for the following reason: " + status );
}
});
}
Daniel is right for the most part, where he is incorrect is his access of the property here:
$('#latitude').val(results[0].geometry.location.Pa)
$('#longitude').val(results[0].geometry.location.Qa)
You should instead use the lat() and lng() functions provided:
$('#latitude').val(results[0].geometry.location.lat())
$('#longitude').val(results[0].geometry.location.lng())
You can use the Google API to get the Longitude and Latitude from your address.
As you already said, you should implement a hidden field where the result should be inserted.
Then you can save the location together with the coordinates.
I recently implemented this function in one of my projects:
function getLatLngFromAddress(city, country){
var address = city +", "+ country;
var geocoder = new google.maps.Geocoder();
geocoder.geocode( { 'address': address}, function(results, status) {
if (status == google.maps.GeocoderStatus.OK) {
$('#latitude').val(results[0].geometry.location.lat());
$('#longitude').val(results[0].geometry.location.lng());
} else {
console.log("Geocode was not successful for the following reason: " + status);
}
});
}

Latitude and longitude can find zip code?

I am using Google geocoder for lat and lon and my question is, is there a way you can find out zipcode with latitude and longitude?
It's good to note that Google Maps has a new version since this solultion was presented.
Reference: https://developers.google.com/maps/documentation/geocoding/?csw=1#ReverseGeocoding
Here's an updated example for Google Maps v3. It makes use of the Address Components that JIssak mentions above. I should note that there is no fallback. If it fails to find a zip code, it does nothing. This may or may not be important to your script.
var latlng = new google.maps.LatLng(p.coords.latitude, p.coords.longitude);
geocoder = new google.maps.Geocoder();
geocoder.geocode({'latLng': latlng}, function(results, status) {
if (status == google.maps.GeocoderStatus.OK) {
if (results[0]) {
for (j = 0; j < results[0].address_components.length; j++) {
if (results[0].address_components[j].types[0] == 'postal_code')
alert("Zip Code: " + results[0].address_components[j].short_name);
}
}
} else {
alert("Geocoder failed due to: " + status);
}
});
I think what you are looking for is the address_components[] in the results array. Maybe something like this would work, just typing the below so it might have errors in it but I think you will get the idea.
http://code.google.com/apis/maps/documentation/geocoding/#Results
function (request, response) {
geocoder.geocode({ 'address': request.term, 'latLng': centLatLng, 'region': 'US' }, function (results, status) {
response($.map(results, function (item) {
return {
item.address_components.postal_code;//This is what you want to look at
}
}
[Removed non-working solution for google - see #hblackorby's solution.]
Here's a version that uses openstreetmap.org, much simpler than google's api - coffeescript, then javascript:
getZip = (cb) ->
# try to populate zip from geolocation/google geocode api
if document.location.protocol == 'http:' && navigator.geolocation?
navigator.geolocation.getCurrentPosition (pos) ->
coords = pos.coords
url = "http://nominatim.openstreetmap.org/reverse?format=json&lat=#{ coords.latitude }&lon=#{ coords.longitude }&addressdetails=1"
$.ajax({
url: url,
dataType: 'jsonp',
jsonp: 'json_callback',
cache: true,
}).success (data) ->
cb(data.address.postcode)
Here's the compiled javascript:
getZip = function(cb) {
if (document.location.protocol === 'http:' && (navigator.geolocation != null)) {
return navigator.geolocation.getCurrentPosition(function(pos) {
var coords, url;
coords = pos.coords;
url = "http://nominatim.openstreetmap.org/reverse?format=json&lat=" + coords.latitude + "&lon=" + coords.longitude + "&addressdetails=1";
return $.ajax({
url: url,
dataType: 'jsonp',
jsonp: 'json_callback',
cache: true
}).success(function(data) {
return cb(data.address.postcode);
});
});
}
};
Use it like this:
getZip(function(zipcode){ console.log("zip code found:" + zipcode); });
Yahoo's PlaceFinder API provides a good wat to lookup location data by lat/lng:
http://developer.yahoo.com/geo/placefinder/
Here's an example url that they use:
http://where.yahooapis.com/geocode?q=38.898717,+-77.035974&gflags=R
It would seem so:
Source: Google Maps API Service
Geocoding is the process of converting addresses (like "1600
Amphitheatre Parkway, Mountain View, CA") into geographic coordinates
(like latitude 37.423021 and longitude -122.083739), which you can use
to place markers or position the map. The Google Geocoding API
provides a direct way to access a geocoder via an HTTP request.
Additionally, the service allows you to perform the converse operation
(turning coordinates into addresses); this process is known as
"reverse geocoding."
You should also check out this documentation which has some sample code:
Reverse Geocoding
I made a generic function to look for the type that you want. Not always the address_component has zipcode, country, etc and if they do not always are in the same index. Sometimes your array is lenght 8, 6 or whatever. I did it in Typescript, just change a few things to make it vanilla JS.
getPlaceTypeValue(addressComponents: Places[], type: string): string {
let value = null;
for (const [i] of addressComponents.entries()) {
if (addressComponents[i].types.includes(type)) {
value = addressComponents[i].long_name;
break;
}
}
return value;
}
OR
getPlaceTypeValue(addressComponents: any[], type: string): string {
return (addressComponents.find(({ types }) => types.includes(type)) || {}).long_name || null;
}
Example of usage:
this.placesService.getPlaceTypeValue(address.address_components, 'postal_code');
this.placesService.getPlaceTypeValue(address.address_components, 'country');