Google Maps reverse geocoding address appears after second click? - javascript

Currently if I click on a marker, error in console shows "address undefined" but if i click it again the address shows up, why is this happening?
What my listener looks like:
map.data.addListener('click', function(event) {
var lat = event.latLng.lat();
var lng = event.latLng.lng();
function getReverseGeocodingData() {
var latlng = new google.maps.LatLng(lat, lng);
// This is making the Geocode request
var geocoder = new google.maps.Geocoder();
geocoder.geocode({ 'latLng': latlng }, function (results, status) {
if (status !== google.maps.GeocoderStatus.OK) {
alert(status);
}
// This is checking to see if the Geoeode Status is OK before proceeding
if (status == google.maps.GeocoderStatus.OK) {
console.log(results[0].formatted_address);
address = (results[0].formatted_address);
}
});
}
getReverseGeocodingData(lat, lng);
infoWindow.setContent("Address: " + address + "<br>Vehicle: " + event.feature.getProperty('deviceID')+"<br> Speed: "+event.feature.getProperty('speedKPH'));
infoWindow.setPosition(event.latLng);
infoWindow.setOptions({pixelOffset: new google.maps.Size(0,-34)});
infoWindow.open(map);
});
thank you for your time and help in advance.

geocoder.geocode works asynchronously, which means the callback will be invoked later™. You are calling this method from the synchronous method getReverseGeocodingData, and then proceed to use the address data immediately afterwards.
This can't work.
Asynchronous communication can be visualized with traditional paper mail. Imagine you send a letter to Google to get the address at x,y. After you put the letter in the postbox, you don't have the result just yet, so you can't print that sign with the address on it yet. But you can do other stuff, like repainting your house (yeah, the metaphor is stretched). You will have to be patient to wait for the answer via mail.
A few days later the mailman rings, and delivers you the answer from Mountain View. It says: "x,y is at Hauptstraße 22". Now you can start printing that sign (and this is where the metaphor ends) to the status bar of your browser.
On the other hand, you can visualize synchronous communication with phone calls. You get the answer immediately, and you can't do anything else during the call. After you hung up, you got the answer.
In JavaScript, we are pretty much stuck with the asynchronous model. If this is good or bad is not for today to decide ;-)

So thanks thriqon i understood the problem,
and have come up with this solution which i'm not sure how correct it is, but it does what i need it to do. It calls for the address once they hover over the point in the background without popping up the infowindow and when they click, tada, the address is shown in the infowindow! hope this helps some people! messsssy code
map.data.addListener('mouseover', function(event) {
var lat = event.latLng.lat();
var lng = event.latLng.lng();
function getReverseGeocodingData(lat, lng) {
var latlng = new google.maps.LatLng(lat, lng);
// This is making the Geocode request
var geocoder = new google.maps.Geocoder();
geocoder.geocode({ 'latLng': latlng }, function (results, status) {
if (status !== google.maps.GeocoderStatus.OK) {
alert(status);
}
// This is checking to see if the Geoeode Status is OK before proceeding
if (status == google.maps.GeocoderStatus.OK) {
console.log(results[0].formatted_address);
address = (results[0].formatted_address);
return address;
}
});
}
getReverseGeocodingData(lat, lng);
map.data.addListener('click', function(event) {
infoWindow.setContent("Address: " + address + "<br>Vehicle: " + event.feature.getProperty('deviceID') +"<br> Speed: "+event.feature.getProperty('speedKPH')+"<br> Heading:"+event.feature.getProperty('heading'));
infoWindow.setPosition(event.latLng);
infoWindow.setOptions({pixelOffset: new google.maps.Size(0,-34)});
infoWindow.open(map);
});
});

Related

How can I keep showing a Js var in HTML after route changes?

I'm bad with Javascript and would like your help!
Hi, I'm building a Rails application and would like to add some features related to geoloction. For that I get the current location of the user with JS and then print it with HTML.
As you guys will see, my code runs every time the page loads, but when my routes change, for example: /about, /settings, /events, it simply disappear and I have to load the page again to print the HTML element.
/* CURRENT LOCATION */
function geolocationSuccess(position) {
var latitude = position.coords.latitude;
var longitude = position.coords.longitude;
var geocoder = new google.maps.Geocoder();
var latlng = {lat: latitude, lng: longitude};
geocoder.geocode({'location': latlng}, function(results, status) {
if (status === google.maps.GeocoderStatus.OK) {
if (results[0]){
var user_address = results[0].formatted_address;
document.getElementById("current_location").innerHTML = user_address;
}else {
console.log('No results found for these coords.');
}
}else {
console.log('Geocoder failed due to: ' + status);
}
});
}
function geolocationError() {
console.log("please enable location for this feature to work!");
}
$(document).ready(function() {
if ("geolocation" in navigator) {
navigator.geolocation.getCurrentPosition(geolocationSuccess, geolocationError);
} else {
alert("Geolocation not supported!");
}
});
How can I have the current location printed on this element in all my application routes?
I wouldn't like to request this information every time.
Maybe a cookie? I don't know...
or request just once every some time
What do you guys recommend? Please help me :)
You can use localStorage for this purpose: https://developer.mozilla.org/en-US/docs/Web/API/Window/localStorage
localStorage allows you to save data between browser sessions and windows.
An example usage might be:
...
// Somewhere in geocode request callback
localStorage.setItem('user_address', results[0].formatted_address)
...
// Somewhere in your render code
document.getElementById("current_location").innerHTML =
localStorage.getItem('user_address')
...

Changing visibility of HTML elements based on geolocation permission [duplicate]

This question already has answers here:
check if location setting has been turned off in users browser
(2 answers)
Closed 3 years ago.
I'm trying to make an HTML element visible if the end user hasn't agreed to let the browser know their location. However, my current code isn't working (nor is the console log) when declining the browser's request. But when allowing the browser to access my location, the API call to Google Places works.
To summarise: If a user declines the browser's request, I want the visibility of geolocationunavail to be visible, rather than hidden.
HTML
<div id="geolocationunavail">
<p>Don't want to share your location?</p>
<p><span>That's cool.</span> Type a location below.</p>
</div>
CSS
#geolocationunavail {
visibility: hidden;
}
JS
function getUserLocation() {
if(navigator.geolocation){
navigator.geolocation.getCurrentPosition(function(position) {
document.querySelector("#longitude").value = position.coords.longitude;
document.querySelector("#latitude").value = position.coords.latitude;
var lng = position.coords.longitude;
var lat = position.coords.latitude;
var latlng = new google.maps.LatLng(lat, lng);
var geocoder = new google.maps.Geocoder();
geocoder.geocode({ 'latLng': latlng }, function (results, status) {
if (status !== google.maps.GeocoderStatus.OK) {
alert(status);
}
if (status == google.maps.GeocoderStatus.OK) {
console.log(results);
var address = (results[0].formatted_address);
document.querySelector("#citysearch").value = address;
}
});
});
} else {
console.log("Geolocation is not supported by this browser.");
document.getElementById("geolocationunavail").style.display = "visible";
}
}
It looks like you have 2 different problems, so I will address them both:
First, your geolocation function is not working as expected. This is happening because you are not using the function correctly. You would not want to use an else statement to say that geolocation is not working, because geolocation will always "work" since it is called successfully regardless of the user input. Even if the user selects "block" the function technically "worked" and therefore will not run the else statement.
Second, your visibility is not toggling correctly. There are 2 ways you can fix this. You can either make it a class and use classList.toggle("myClass"), or you can do document.getElementById('geolocationunavil').style.visibility = 'visible';
Both of these put together will result in:
function getUserLocation() {
navigator.geolocation.getCurrentPosition(
position => {
document.querySelector("#longitude").value = position.coords.longitude;
document.querySelector("#latitude").value = position.coords.latitude;
var lng = position.coords.longitude;
var lat = position.coords.latitude;
var latlng = new google.maps.LatLng(lat, lng);
var geocoder = new google.maps.Geocoder();
geocoder.geocode({ 'latLng': latlng }, function (results, status) {
if (status !== google.maps.GeocoderStatus.OK) {
alert(status);
}
if (status == google.maps.GeocoderStatus.OK) {
console.log(results);
var address = (results[0].formatted_address);
document.querySelector("#citysearch").value = address;
}
});
},
err => {
console.log("Geolocation is not supported by this browser.");
document.getElementById("geolocationunavail").style.visibility = "visible";
})
}

Trigger JavaScript error when geo location services disabled

In my AngularJS project I am using the following code to get a device's GPS co-ordinates:
// when user clicks on geo button
$scope.getGeoLocation = function() {
var geocoder = new google.maps.Geocoder();
window.navigator.geolocation.getCurrentPosition(function(position) {
$scope.$apply(function() {
$scope.position = position;
var latlng = new google.maps.LatLng($scope.position.coords.latitude, $scope.position.coords.longitude);
geocoder.geocode({'latLng': latlng}, function(results, status) {
if (status == google.maps.GeocoderStatus.OK) {
$scope.searchstring = results[2].formatted_address;
$location.search('s', $scope.searchstring);
$location.search('p', 1);
$location.search('geo', true);
$route.reload();
}
});
});
}, function(error) {
$scope.error = error;;
});
};
The problem is when location services is turned off on an iPhone 6, there is a no error created to inform the user that they need to turn on location services.
Does any one know how I can amend the code above to trigger an error in this scenario? Any help would be much appreciated.
As pointed out in this post Is there a way to check if geolocation has been DECLINED with Javascript?, you can pass a second callback to getCurrentPosition which will get called if the permission is declined.
Thanks for pointing me in the right direction unobf. Please find attached the code (with updated error handling) in case any one stumbles across this.
// when user clicks on geo button
$scope.getGeoLocation = function() {
var geocoder = new google.maps.Geocoder();
window.navigator.geolocation.getCurrentPosition(function(position) {
$scope.$apply(function() {
$scope.position = position;
var latlng = new google.maps.LatLng($scope.position.coords.latitude, $scope.position.coords.longitude);
geocoder.geocode({'latLng': latlng}, function(results, status) {
if (status == google.maps.GeocoderStatus.OK) {
$scope.searchstring = results[2].formatted_address;
$location.search('s', $scope.searchstring);
$location.search('p', 1);
$location.search('geo', true);
$route.reload();
}
});
});
}, function(error) {
$scope.error = "";
// Check for known errors
switch (error.code) {
case error.PERMISSION_DENIED:
$scope.error = "This website does not have permission to use " +
"the Geolocation API.";
alert("Geo location services appears to be disabled on your device.");
break;
case error.POSITION_UNAVAILABLE:
$scope.error = "The current position could not be determined.";
break;
case error.PERMISSION_DENIED_TIMEOUT:
$scope.error = "The current position could not be determined " +
"within the specified timeout period.";
break;
}
// If it's an unknown error, build a $scope.error that includes
// information that helps identify the situation, so that
// the error handler can be updated.
if ($scope.error == "")
{
var strErrorCode = error.code.toString();
$scope.error = "The position could not be determined due to " +
"an unknown error (Code: " + strErrorCode + ").";
}
});
};

running a function after a google map call has finished

I'm trying to collect location data from my users as they're entering other details in a form. So I have a google map which users can move a marker about on but I also have an input which they can type a location into.
When they click to submit the form, I want to first geocode the location they have typed and update the hidden lat lng inputs in my form before the submit actually takes place.
I know there's lots of info online but I've read loads of tutorials but I'm struggling to understand or at least to apply the tutorials to my situation.
So when a user clicks submit I want to run geocode and only submit the form when geocode is definitely finished.
$('.submitButton').click(function () {
geocode();
$("#searchForm").submit();//Then submit when geocode finishes
});
And the geocode function
function geocode(){
geocoder.geocode({
address: $('#address').val()
}, function(results, status){
if(status == google.maps.GeocoderStatus.OK){
var geoPoint = new google.maps.LatLng(results[0].geometry.location.lat(), results[0].geometry.location.lng());
map.setCenter(geoPoint);
circle.setCenter(geoPoint);
marker.setPosition(geoPoint);
$('#lat').val(geoPoint.lat());
$('#lng').val(geoPoint.lng());
} else{
alert("Can not geolocate this address.");
}
});
}
Can someone explain to me what I need to do in simple javascript dummy language? THanks
Because Geocoding service is asynchronous, geocode() will return almost immediately and $("#searchForm").submit() will submit what is available and that will be wrong (old or undefined data).
You have to move form submit call to geocode() function just after settings of lat/lng values:
...
marker.setPosition(geoPoint);
$('#lat').val(geoPoint.lat());
$('#lng').val(geoPoint.lng());
$("#searchForm").submit();
} else{
...
If, as you said in comment, geocode() function is also used somewhere else then you will have to write another function with similar functionality or prepare two different callback function.
You may pass an optional argument to geocode, e.g. a function that will be executed on success:
$('.submitButton').click(function (e) {
e.preventDefault();
//call geocode and pass the desired function as argument
geocode(function(){$("#searchForm").submit();});
return false;
});
function geocode(fnc){
geocoder.geocode({
address: $('#address').val()
}, function(results, status){
if(status == google.maps.GeocoderStatus.OK){
var geoPoint = new google.maps.LatLng(results[0].geometry.location.lat(),
results[0].geometry.location.lng());
map.setCenter(geoPoint);
circle.setCenter(geoPoint);
marker.setPosition(geoPoint);
$('#lat').val(geoPoint.lat());
$('#lng').val(geoPoint.lng());
//check if the fnc-argument is a function,
//when it does, execute the function
if($.type(fnc)==='function'){
fnc();
}
} else{
alert("Can not geolocate this address.");
}
});
}

Google Maps V3 API reserve geocode - Unknown property <latlng>

On my map I have some Markers. Onclick I want to get the markers address using reserve geocoding.
Here is my function:
...
google.maps.event.addListener(marker_obj[ii], 'click', function(){
show_marker_information(this);
});
...
function show_marker_information(obj){
//obj = marker
if(typeof(infowindow) != 'undefined')
infowindow.close();
var latlng_search = obj.getPosition();
var geocoder = new google.maps.Geocoder();
geocoder.geocode({
'latlng': latlng_search
},
function(results, status){
alert(results.toSource());
}
);
When clicking on a marker firebug tells me:
Unknown property <latlng>
[Break On This Error] J.toSpan=function(){return new P(this....n(d){return d==k&&c||d instanceof a}}
Any ideas?
I found my error:
geocoder.geocode({
'latlng': latlng_search
},
function(results, status){
alert(results.toSource());
}
);
there is no 'latlng' property at geocoder. it has to be 'location' instead of 'latlng'.

Categories