Geoloacation in IE


I'm going to keep this post fairly short as the Geo Location api is pretty simple and the has been a lot written already about it. However I haven't seen much write about particularly 1 little gotcha in I.E. 9+.

So lets dig into the code, firstly for the older browsers we need to run a quick check to make sure they are compatible. For this you can either use modernizr or you can run the check yourself like so:

if(window.navigator && window.navigator.geolocation){
// Execute Geolocation
} else {
// Fallback
}

So far so good, so easy. Next we need to add actual gelocation code, which is pretty simple also:

success_func = function(data) {
console.log("data", data)
}
error_func = function(error){
console.log("error", error)
}
window.navigator.geolocation.getCurrentPosition(success_func, error_func)

We call getCurrentPosition function and then pass it a success function and error function. You can use anonymous functions, but I prefer it this way as it's easier to test.

So assuming the location is successful, you'll get a object returned with various information, like time stamp, accuracy, etc. The most important will be the lng/lat which you can process like so:

success_func = function(data) {
console.log("data", data)
lng = data.coords.longitude
lat = data.coords.latitude
}

Now to the error function, now this will pass an object with a human friendly error message, an error code and list of the errors. There is currently 3 kinds of errors which are fairly self explanatory:

  1. Permission Denied
  2. Position Unavailable
  3. Timeout

So you can deal with this in your error function like so:

error_func = function(error) {
console.log("error", error.message) //Human friendly message
switch(error.code){
case 1
//Do something after user denied
break;
case 2
// Do something after position unavailable
break;
case 3
// Do something after a timeout
break;
else
//fallback
}
}

Again nothing crazy there, but now on to IE.

IE issue

So in anything less than IE9 geolocation doesn't work, so will handled by our if statement. However in IE9 and above have geolocation, great right? Yes but there is an interesting little issue here, let me try and explain. Triggering a geolocation.getCurrentPosition call for the first time will display a prompt to the user. This will ask them to either accept or deny your site having access to the location data. If they hit accept then it will start locating. If they hit deny permission then the error function is triggered with code 1 "Permission Denied". IE like other browsers works like this, so far so good. But on these prompts there is also a close button that closes the prompt without the user accepting or denying there location. In all browsers except IE this is taken to mean the user is denying location and the error function is call. In IE however nothing is called and the request will simply hang, so we can't fall back to any anything. Great thanks Microsoft!

So how do we work round this? The best solution I have found is to build in a timeout function, great I hear you say isn't there one built in to the request. Well yes there is but the error code 3 is only called when a geo-location request has been accepted and then doesn't complete. In this instance, if the user closes the prompt the geo-location isn't actually called, so unfortunately this won't work. In order work round this we need to slightly change our approach and use watchPostition instead of getCurrentPosition.

So if we look at the code it looks like this:

var geoLoc = navigator.geolocation;
var geoID = geoLoc.watchPosition(
function (p){
success_func(that)
geoLoc.clearWatch(geoID)
},
function(e){
error_func(e)
},
{
enableHighAccuracy: false,
timeout: 5000,
maximumAge: 0
}
);

Now this is like getCurrentPostion, except that we can add it to a variable. So on success we are using clearWatch to cancel the request. This is because unlike getCurrentPosition, watchPosition will continue to check the users position unless we cancel it.

However this does not fix our issue, but it allows us to now to add in our own timeout which will:

var geoLoc = navigator.geolocation;
var location_timeout = setTimeout(function(){
geoLoc.clearWatch(geoID);
getError({code:3, message:"Request timed out"})
}, 50000);

So after 5 secs the timeout is triggered and we flush the geolocation request and fall back to our error function.

This means if anyone closed the prompt we can gracefully fallback rather than leaving the request hanging.

One final note, don't forget to clear the timeout if there request is accepted/failed in the normal way in the success/error functions.


0 Comment


Got Something to Say?

Don’t use these services? Create an account or