I thought I understood how the default operand worked in JavaScript, but clearly not. I'm trying to first determine the user's geographic position, and load a map centered on those coordinates. If the device is unable to determine those coordinates, it would fallback to just loading the map with some default values.
You'll notice that in my error method, I'm calling gMap.init() with no arguments, which I thought should mean that the variables lat and lon should be set to 57.700992 and 11.893836 respectively. Instead, I'm getting Uncaught TypeError: Cannot read property 'coords' of undefined. Where am I going wrong?
Also, in theApp.init() I'm calling the map if navigator.geolocation exists. Does that mean browsers that don't support HTML5 geolocation will not even try loading the map?
var gMap = {
init: function (position) {
var lat = position.coords.latitude || 57.700992,
lon = position.coords.longitude || 11.893836,
geocoder = new google.maps.Geocoder(),
mapOptions = {
zoom: 12,
center: new google.maps.LatLng(lat, lon)
},
map = new google.maps.Map(document.getElementById('mapcanvas'), mapOptions);
},
error: function () {
console.log('failed to retrieve geoposition');
gMap.init();
}
}
var theApp = {
init: function () {
if (navigator.geolocation) {
navigator.geolocation.getCurrentPosition(gMap.init, gMap.error, {timeout:10000});
}
}
}
The || you have there should work, unless position.coords or position is undefined. In that case, JavaScript will throw a error because you're trying to access a property on a undefined object.
You will have to manually check if the objects exist:
var lat, lon;
if(position && position.coords){
lat = position.coords.latitude || 57.700992;
lon = position.coords.longitude || 11.893836;
}
If position is undefined, the if will abort, without trying to check for position.coords.
(The && doesn't evaluate the right parameter, if the left one is false)
And yes, if navigator.geolocation is undefined, the map will not be loaded:
navigator.geolocation.getCurrentPosition(gMap.init, gMap.error, {timeout:10000});
This ^ will not be executed, so gMap.init will not be executed.
You should try
var lat = position.coords.latitude ? window['position'] != undefined : 57.700992,
lon = position.coords.longitude ? window['position'] != undefined : 11.893836,
instead of ||
Related
First time trying to hack together some Javascript here so any resources that will help me understand my problem case is appreciated.
I'm trying to extract the lat and long from the following request to use in another request:
var placeSearch, autocomplete;
var x = document.getElementById("location");
function initAutocomplete() {
// Create the autocomplete object, restricting the search predictions to
// geographical location types.
autocomplete = new google.maps.places.Autocomplete(
document.getElementById('autocomplete'), { types: ['geocode'] });
// Avoid paying for data that you don't need by restricting the set of
// place fields that are returned to just the address components.
autocomplete.setFields(['geometry']);
}
function showPosition() {
x.innerHTML = "Latitude: " + autocomplete.result.geometry.lat +
"<br>Longitude: " + autocomplete.result.geometry.lng;
}
/*
"result" : {
"geometry" : {
"location" : {
"lat" : 51.46588129999999,
"lng" : -0.1413263
}
}
*/
// Bias the autocomplete object to the user's geographical location,
// as supplied by the browser's 'navigator.geolocation' object.
function geolocate() {
if (navigator.geolocation) {
navigator.geolocation.getCurrentPosition(function (position) {
var geolocation = {
lat: position.coords.latitude,
lng: position.coords.longitude
};
var circle = new google.maps.Circle(
{ center: geolocation, radius: position.coords.accuracy });
autocomplete.setBounds(circle.getBounds());
});
}
}
When a user selects the autocompleted location the google api makes a request to:
https://maps.googleapis.com/maps/api/place/js/PlaceService.GetPlaceDetails on the selected location. I can see this returns my desired data here:
Obviously autocomplete.result.geometry.lat returns a location_search.js:18 Uncaught TypeError: Cannot read property 'geometry' of undefined error so I'm missing some knowledge here.
Thank you for your help.
I've implemented something very similar to your needs in my project recently. It's quite easy but it took me a while to realise how to do it.
Basically, you can simply use the .getPlace() method on the Autocomplete object and go from there. Here's how I got the latitude and longitude:
let locationInfo = autocomplete.getPlace().geometry.location;
let latitude = locationInfo.lat();
let longitude = locationInfo.lng();
In your specific case you should change your showPositions function to
function showPosition() {
x.innerHTML = "Latitude: " + autocomplete.getPlace().geometry.location.lat +
"<br>Longitude: " + autocomplete.getPlace().geometry.location.lng;
}
Does this do the trick?
im using the Google API, i want to make it that there can be multiple addresses marked on the map so im using the Geocoder. However the rest of my code is running before this Geocoder returns the result it seems!
// Handle addresses
var addressesHandled = [];
function handleAddresses(addressObj) {
for (i = 0; i < addressObj.length; i++) {
addressesHandled[i] = new Address(addressObj[i]['title'], addressObj[i]['address'], addressObj[i]['latlng'], addressObj[i]['defaultOpen']);
}
}
// Address object
function Address(title, address, latlng, defaultOpen) {
this.title = title;
this.address = address;
this.latlng = latlng;
if (latlng == undefined) {
this.latlng = codeAddress(address);
}
this.defaultOpen = defaultOpen;
}
As you can see im going through each object and getting the address if the lat and lng values are undefined. If these are undefined I then execute the codeAddress function which will get the lat and lng values from the current address, however I think that the rest of the script is still running whilst this happens!
Below is the codeAddress function, I thought I was unable to the return the result however now I believe that it simply isn't being returns quick enough.
How can I fix this issue so the rest of my script waits until each address has had it's lat and lng calculated!?
function codeAddress(address, callback) {
var geocoder;
geocoder = new google.maps.Geocoder();
geocoder.geocode( { 'address': address}, function(results, status) {
if (status == google.maps.GeocoderStatus.OK) {
var loc = [];
// loc = { lat: results[0].geometry.location.lat(), lng: results[0].geometry.location.lng() };
loc[0] = results[0].geometry.location.lat(); loc[1] = results[0].geometry.location.lng();
console.log(loc);
callback(loc);
} else {
console.log("Geocode was not successful for the following reason: " + status);
}
});
}
Edit:
Hmm, I just thought would it be easier just to process the marker and add it to the map as each geocode function has it's result returned ?
Can someone look at my code and tell me what I'm doing wrong? I understand that the Googlemaps geocoder is an async function so there needs to be a callback to handle the results. So I'm following the example here but I still can't get it to work:
How do I return a variable from Google Maps JavaScript geocoder callback?
I want to give my codeAddress function an actual address and a callback function. If the results array has something I send the lat and lng to the callback function.
codeAddress = function(address, callback) {
var gpsPosition = {};
if (geocoder) {
geocoder.geocode({'address': address}, function(results, status) {
if (status == google.maps.GeocoderStatus.OK) {
if (results[0]) {
console.log("got results!");
var lat = results[0].geometry.location['B'];
var lng = results[0].geometry.location['k'];
callback(lat, lng);
} else {
alert("No results found");
}
} else {
alert("Geocoder failed due to: " + status);
}
});
}
};
This is the callback function. Basically it takes the lat and lng from the codeAddress function and puts the lat and lng into a hash and returns it. The idea is to then store the hash into a variable called location and reference location when I'm creating a new map marker.
createGPSPosition = function(lat, lng){
console.log("createGPSPosition called with lat and lng:");
console.log(lat);
console.log(lng);
var gpsPosition = {};
gpsPosition.B = lat;
gpsPosition.k = lng;
console.log("gpsPosition:");
console.log(gpsPosition);
return gpsPosition;
};
When I run this code console.log(gpsPosition); actually logs the final hash object. But I still don't see the object getting returned... so when I do:
var stuff = codeAddress("1600 Amphitheatre Pkwy, Mountain View, CA 94043", createGPSPosition)
stuff still turns up as undefined. What's going on here?
This problem is that you're expecting asynchronous code to work in a synchronous way. stuff is defined before codeAddress finishes searching. The simplest solution is to provide a different callback, define stuff within that and use it there. This should work fine:
codeAddress("1600 Amphitheatre Pkwy, Mountain View, CA 94043", function(lat, lng){
var stuff = createGPSPosition(lat, lng);
console.log(stuff); // => your gpsPosition object
});
An alternative would be to learn Promises.
I'm looking for a way to trigger user geolocation navigator function from another function mapInit(). It nearly works, but I can't have a proper callback of getCurrentPosition() to confirm it went well.. it return undefined each times.
My geolocation object will have to achieve other tasks so I don't want it to trigger mapInit(). It should have to get user location, record it and return trueor false.. Any guess?
Thanks :)
// Get user current position, return true or false
//
var geolocation = {
get: function() {
if (alert(navigator.geolocation.getCurrentPosition(this.success, this.error, {
enableHighAccuracy: true,
maximumAge: 5000
})) {
return true;
} else {
return false;
}
},
success: function(position) {
this.last = position; // record last position
return true;
},
error: function() {
alert('code: ' + error.code + 'n' + 'message: ' + error.message + 'n')
return false;
},
last: undefined,
}
// Initialize leaflet map and get user location if coords are undefined
//
var mapInit = function(latitude, longitude) {
if (!latitude && !longitude) { // if no latlng is specified, try to get user coords
if (geolocation.get()) {
latitude = geolocation.last.coords.latitude;
longitude = geolocation.last.coords.longitude;
} else {
alert('oups!');
}
}
var map = L.map('map').setView([latitude, longitude], 15);
L.tileLayer('http://{s}.tile.cloudmade.com/#APIKEY#/68183/256/{z}/{x}/{y}.png', {
minZoom: 13,
maxZoom: 16,
}).addTo(map);
var marker = L.marker([latitude, longitude]).addTo(map);
}
Not sure I understand what you're trying to do but when you call "getCurrentPosition" the first argument you pass is a method that will be called with the Position once it is retrieved. As you said in your comment getCurrentPosition will always return immediately but the callback method will be called if the user position can be retrieved (it may never be called):
navigator.geolocation.getCurrentPosition( function(position) {
var lat = position.coords.latitude;
var lon = position.coords.longitude;
//do something like recent the Map
});
You will need to create the Leaflet Map first with some default coordinates and then recenter the map with the coordinates provided to the callback method.
I have a serious problem that i have been trying to debug for a few days already.
I have a script that gets users current latitude and longitude, and then stores them in variables. however, when i try to use these variables outside this function and in the //init map zone, the map is just not showing up. by alerting out the variables i can see that outside the position function variables are set to "Undefined". here is my code:
//main function here
function initialize() {
var lat;
var lon;
//check if user has geo feature
if(navigator.geolocation){
navigator.geolocation.getCurrentPosition(
//get position
function(position){
lat = position.coords.latitude;
lon = position.coords.longitude;
},
// if there was an error
function(error){
alert('ouch');
});
}
//case the users browser doesn't support geolocations
else {
alert("Your browser doesn't support geolocations, please consider downloading Google Chrome");
}
//init map
var myOptions = {
center: new google.maps.LatLng(lat, lon),
zoom: 16,
mapTypeId: google.maps.MapTypeId.ROADMAP
};
var map = new google.maps.Map(document.getElementById("map_canvas"),
myOptions);
}
Thanks for any help, Ariel
That is because you declare your variables within the function. The variables gets private to the initialize function and can only be accessed from within it. If you need to be able to access your variables outside of the initialize function, then move the variable declaration out of the function.
var lat;
var lon;
function initialize() {
...
Have a look at this MDN article about variable scope in JavaScript.
UPDATE
Looking through the code again I realize that the problem isn't variable scope, got confused by the indentation. I'm not familiar with the Geolocation API but I believe that the problem might be that the navigator.geolocation.getCurrentPosition() is asynchronous, as it will have to wait for the user to allow the website to get the position of the device. Therefor myOptions will have been assigned before the actual position have been retrieved - thus lat & lng are still undefined when myOptions is assigned.
Try this instead:
//main function here
function initialize() {
var lat, lon, map, myOptions;
//check if user has geo feature
if(navigator.geolocation){
navigator.geolocation.getCurrentPosition(
//get position
function(position){
lat = position.coords.latitude;
lon = position.coords.longitude;
//init map
myOptions = {
center: new google.maps.LatLng(lat, lon),
zoom: 16,
mapTypeId: google.maps.MapTypeId.ROADMAP
};
map = new google.maps.Map(document.getElementById("map_canvas"),
myOptions);
},
// if there was an error
function(error){
alert('ouch');
});
}
//case the users browser doesn't support geolocations
else {
alert("Your browser doesn't support geolocations, please consider downloading Google Chrome");
}
}
More of a correction on the other answer. The issue of scope is not relevant. As defined in the original code lat and lon are in scope in the context to which the question author is using alert.
Here's a runnable example that proves it.
function getPos( f ) {
var position = new Object();
position.coords = new Object();
position.coords.latitude = 5;
position.coords.longitude = 10;
f( position );
}
function initialize() {
var lat;
var lon;
getPos(
function(position){
lat = position.coords.latitude;
lon = position.coords.longitude;
}
);
alert( lat + " " + lon );
}
initialize(); //expected 5 & 10
Anyways, this doesn't seem to be a pure JS issue. This seems to be an issue with whatever google api you are using. This question should have been tagged with such, as I have no knowledge of this API or whether you're calling it wrong or not.