So I have this javascript code. In safari and chrome, if user declines to share location, it goes to fail function as it should; however, in Firefox, it does not.
Any helps appreciated.
function initGeolocation()
{
if( navigator.geolocation )
{
// Call getCurrentPosition with success and failure callbacks
navigator.geolocation.getCurrentPosition( success, fail );
}
else
开发者_运维问答 {
alert("Sorry, your browser does not support geolocation services.");
}
}
var map;
function success(position)
{
var longIDText = document.getElementById('longID');
var latIDText = document.getElementById('latID');
longIDText.value = position.coords.longitude;
latIDText.value = position.coords.latitude;
document.getElementById('coordSubmitID').click();
}
function fail(error)
{
alert("FAAAAAAAAAAIIIIIIIIIL")
var zip_code ;
while (true){
// Could not obtain location
zip_code = prompt("Please enter your current address or zip code","");
if ( zip_code == "" ) {
alert(zip_code +" is not a valid address. Please try again.");
}
else{
break;
}
}
var zipIDText = document.getElementById('zipID');
zipIDText.value = zip_code;
document.getElementById('coordSubmitID').click();
}
For Firefox it seems that PERMISSION_DENIED
is raised only if "Never share" is selected; if the dialog is dismissed or "Not now" is selected, effectively nothing happens - even on mozillas geolocation demo if you dismiss the permissions UI nothing happens.
This means that getCurrentPosition
can return either because the user closed the confirmation UI, or because it successfully started it asynchronous request - there doesn't appear to be a way to discriminate between the two.
https://bugzilla.mozilla.org/show_bug.cgi?id=675533
This is a real pain, and definately not desirable functionality.
The workaround I am using to save the user waiting for ever is to set a timeout to check if the wait spinner is showing after 3 seconds, and if so, hide it and show a manual zip code input:
var latlng;
var waitTime = 3000;
try {
if (navigator.geolocation) {
navigator.geolocation.getCurrentPosition(function (position) {
success(position);
}, showError);
} else {
showError("NOT-SUPPORTED");
}
var t = setTimeout(function () {
if ($("#getZip div.loading").css("display") != "none") {
$("#getZip div.loading").hide();
$("#errorZip").show();
}
}, waitTime);
} catch (evt) {
alert(evt);
}
As alexleonard pointed out, the only reliable, cross-browser solution I've found for this is to have a setTimeout()
to check the state of your latLng
object/variables, as the timeout
option of getCurrentPosition()
doesn't seem to work reliably. The example below was tested in IE11, Chrome33 and Firefox28.
For a more complete solution that uses a jQuery promise, check out my Gist here: https://gist.github.com/GFoley83/10092929
Example - Hit F12, paste into the console and run
var latLng,
geoOptions = {
enableHighAccuracy: false,
timeout: 5000, // Wait 5 seconds
maximumAge: 300000 // Valid for 5 minutes
};
var userLocationFound = function(position){
latLng = {
lat: position.coords.latitude,
lng: position.coords.longitude
};
window.console.log("User confirmed! Location found: " + latLng.lat + ", " + latLng .lng);
}
var userLocationNotFound = function(){
latLng = {
lat: -41.29247, // fallback lat
lng: 174.7732 // fallback lng
};
window.console.log("Fallback set: ", latLng);
}
window.navigator.geolocation.getCurrentPosition(userLocationFound, userLocationNotFound, geoOptions);
setTimeout(function () {
if(!latLng){
window.console.log("No confirmation from user, using fallback");
userLocationNotFound();
}else{
window.console.log("Location was set");
}
}, geoOptions.timeout + 1000); // Wait extra second
This is as per design and apparently is a non-issue. See https://bugzilla.mozilla.org/show_bug.cgi?id=675533
It is left to the developers using the feature to come up with a browser-specific work around for Firefox.
Of note, based on the comment by the FF developer about actual geolocation usage by end users, apparently the Firefox developers are gathering detailed data about what end users are doing with their products.
Note that this is actually also an issue in Chrome.
In Chrome an advisory notice appears "site wants to know your location" - it then offers "Allow" and "Deny" as options. With the UI design, the user is more likely to choose either Allow or Deny, which will then return an answer to the navigator.geolocation.getCurrentPosition function. However, the user can also click an "X" on the far right of the advisory notice. This is essentially the same as clicking "Not now" in Firefox.
No result is returned to the function.
Looks like a timer has to be implemented to allow for this possible outcome.
Use a promise. I'm using angularjs that has it's own version of $q to solve the same issue we are all having.
$scope.ByUserPosition = function () {
//http://www.w3.org/TR/geolocation-API/
var deferred = $q.defer();
deferred.promise.then(findByPosition, function (data) {
console.log('error', data);
});
var resolveBy = 1000 * 30;
navigator.geolocation.getCurrentPosition(function (position) {
deferred.resolve({ latitude: position.coords.latitude, longitude: position.coords.longitude });
}, function (err) {
deferred.reject(err);
}, {
enableHighAccuracy: true,
timeout: resolveBy,
maximumAge: 0
});
$timeout(function() {
deferred.reject('timed out');
}, resolveBy)
};
Edit (after a downvote) 6-11-2013
As remarked below this answer, this does not solve the problem when a user denies access to location. To the downvote is correct. I keep the answer here, because the timeout is soemthing one should use anyway, and I do not see it in any answer.
The function navigator.geolocation.getCurrentPosition() has the option to send the timeout with it:
navigator.geolocation.getCurrentPosition(
function (position){
//do someting with position
},
function (error){
// do something with the error (like the code)
},
{timeout:10000}
);
and some other options, like the age of the cached position (maximumAge). the timeout and maximumage are in milliseconds, so 10000 = 10 secs.
By the way, the default timeout is infinite... so if you do not set the timeout, it will never call the callback for errors....
so in the option like Jamie answered, I would say:
if (navigator.geolocation) {
navigator.geolocation.getCurrentPosition(function (position) {
success(position);
}, showError, {timeout:3000});
}
The only solution to this problem is as follows:
- When the user clicks the button to get his location automatically, show the spinner and a link beside it "ex: Cancel".
- If he enables sharing location, then no problem. If he decides to dismiss Firefox popup, the spinner would still be shown but he can click "Cancel" link to stop the spinner an an indicator for dismissing the popup
I hope this helps :)
Here's a solution to my problem using vanilla es6 Promises
. Inspired by @LeblancMeneses response.
if(navigator.geolocation) {
let promise = new Promise((resolve, reject) => {
navigator.geolocation.getCurrentPosition(
(position) => {
resolve(position)
},
(error) => {
resolve(error)
}
)
window.setTimeout(() => {
resolve({})
}, 8000)
})
promise.then((result) => {
// do something with result
})
} else {
console.log('no geolocation available')
}
var latlng;
if (navigator.geolocation) {
navigator.geolocation.getCurrentPosition(function (position) {
latlng = new google.maps.LatLng(position.coords.latitude, position.coords.longitude);
});
}
if(!latlng) {
latlng = new google.maps.LatLng(57.718, 11.974);
}
Handeld all my errors :)
watchPosition and getCurrentPosition both accept a second callback which is invoked when there is an error. The error callback provides an argument for an error object. For permission denied, error.code would be error.PERMISSION_DENIED (numeric value 1).
Read more here: https://developer.mozilla.org/en/Using_geolocation
Example:
navigator.geolocation.watchPosition(function(position) {
console.log("i'm tracking you!");
},
function (error) {
if (error.code == error.PERMISSION_DENIED)
console.log("you denied me :-(");
});
精彩评论