navigator.geolocation.getCurrentPosition sometimes works sometimes doesn't

So I have a pretty simple bit of JS using the navigator.geolocation.getCurrentPosition jammy.

$(document).ready(function(){
  $("#business-locate, #people-locate").click(function() {
    navigator.geolocation.getCurrentPosition(foundLocation, noLocation);
  });

  navigator.geolocation.getCurrentPosition(foundLocation, noLocation);

  function foundLocation(position) {
    var lat = position.coords.latitude;
    var lon = position.coords.longitude;
    var userLocation = lat + ', ' + lon;
    $("#business-current-location, #people-current-location").remove();
    $("#Near-Me")
      .watermark("Current Location")
      .after("<input type='hidden' name='business-current-location' id='business-current-location' value='"+userLocation+"' />");
    $("#people-Near-Me")
      .watermark("Current Location")
      .after("<input type='hidden' name='people-current-location' id='people-current-location' value='"+userLocation+"' />");
  }
  function noLocation() {
    $("#Near-Me").watermark("Could not find location");
    $("#people-Near-Me").watermark("Could not find location");
  }
})//end DocReady

Basically what's happening here is we get the current position, if it's obtained, two "watermarks" are placed in two fields that say "Current Position" and two hidden fields are created with the lat-long data as their value (they're removed in the beginning so they don't get duplicated every time). There are also two buttons that have a click function tied to them that do the same thing. Unfortunately, every third time or so, it works. What's the problem here???


Solution 1:

I have been having exactly the same problem, and finding almost no information online about it. Nothing at all in the books. Finally I found this sober query on stackoverflow and (ha!) it was the final impetus I needed to set up an account here.

And I have a partial answer, but alas not a complete one.

First of all, realise that the default timeout for getCurrentPosition is infinite(!). That means that your error handler will never be called if getCurrentPosition hangs somewhere on the back end.

To ensure that you get a timeout, add the optional third parameter to your call to getCurrentPosition, for example, if you want the user to wait no more than 10 seconds before giving them a clue what is happening, use:

navigator.geolocation.getCurrentPosition(successCallback,errorCallback,{timeout:10000});

Secondly, I have experienced quite different reliability in different contexts. Here at home, I get a callback within a second or two, although the accuracy is poor.

At work however, I experience quite bizarre variations in behavior: Geolocation works on some computers all the time (IE excepted, of course), others only work in chrome and safari but not firefox (gecko issue?), others work once, then subsequently fail - and the pattern changes from hour to hour, from day to day. Sometimes you have a 'lucky' computer, sometimes not. Perhaps slaughtering goats at full moon would help?

I have not been able to fathom this, but I suspect that the back end infrastructure is more uneven than advertised in the various gung-ho books and websites that are pushing this feature. I really wish that they would be a bit more straight about how flakey this feature is, and how important that timeout setting is, if you want your error handler to work properly.

I have been trying to teach this stuff to students today, and had the embarassing situation where my own computer (on the projector and several large screens) was failing silently, whereas about 80% of the students were getting a result almost instantly (using the exact same wireless network). It's very difficult to resolve these issues when my students are also making typos and other gaffes, and when my own pc is also failing.

Anyway, I hope this helps some of you guys. Thanks for the sanity check!

Solution 2:

This is the hacky way that I am getting around this, at least it works in all current browsers (on Windows, I don't own a Mac):

if (navigator.geolocation) {
    var location_timeout = setTimeout("geolocFail()", 10000);

    navigator.geolocation.getCurrentPosition(function(position) {
        clearTimeout(location_timeout);

        var lat = position.coords.latitude;
        var lng = position.coords.longitude;

        geocodeLatLng(lat, lng);
    }, function(error) {
        clearTimeout(location_timeout);
        geolocFail();
    });
} else {
    // Fallback for no geolocation
    geolocFail();
}

This will also work if someone clicks the close or chooses no or chooses the Never Share option on Firefox.

Clunky, but it works.

Solution 3:

This works for me every time:

navigator.geolocation.getCurrentPosition(getCoor, errorCoor, {maximumAge:60000, timeout:5000, enableHighAccuracy:true});

Though it isn't very accurate. The funny thing is that on the same device if I run this it puts me off about 100 meters (every time), but if I go to google's maps it finds my location exactly. So although I think the enableHighAccuracy: true helps it to work consistently, it doesn't seem to make it any more accurate...