Example of iPhone Geolocation with jQuery

This post is more than 2 years old.

At lunch today I took a quick look at how Safari on the iPhone handles Geolocation. If you have an iPhone (you know, that device that doesn't play Flash?) then you've probably seen applications that ask permission to locate your position. The hardware supports it both for applications but web pages as well. I was curious to see a) how difficult it would be to use and b) if it could degrade nicely for other clients.

So to begin, I found an excellent blog post that demonstrated a simple example of the code: How to Use Geolocation in Mobile Safari.

His code sample was simple and to the point:

navigator.geolocation.getCurrentPosition(foundLocation, noLocation);

function foundLocation(position) { var lat = position.coords.latitude; var long = position.coords.longitude; alert('Found location: ' + lat + ', ' + long); } function noLocation() { alert('Could not find location'); }

Basically - run a getCurrentPosition and pass it a pass/fail operator. I tested this just to ensure it worked and it did perfectly. Using that as a base I began to work on a simple application.

My idea was simple - I'd tie onto Yahoo's Local Search API. I'd have a form where you could enter "pizza", and because we knew your longitude/latitude, we could pass that to Yahoo. To support browsers/clients that couldn't use this, I'd use jQuery to simply ask the user for their location. This works because Yahoo's APIs supports both a precise location, or a precise street/city/state, as well as a loose "location" argument. Kudos to Yahoo for being so flexible.

Before I go further - one thing I don't like about JavaScript based blog entries is that it's sometimes difficult to explain the process. The code I'm going to show was done over multiple iterations, but since I didn't save each and every edit, your only going to see the final result. Do know that I certainly didn't write it out like this - it took more than one try to get it right.

That being said - let's begin with the view area:

<form id="searchForm"> Search for: <input type="text" id="term" value="pizza"> </form> <input type="button" id="searchBtn" value="Search" disabled="true">

<div id="results"></div>

Nothing too fancy here. You can see a form with a search field, a button (I'll explain why I put it outside the form in a PS), and a div for my results. Now let's go up to my JavaScript.

<script> var lat = ""; var long = "";

function foundLocation(position) { lat = position.coords.latitude long = position.coords.longitude $("#searchBtn").attr("disabled", false) $("#results").html("") }

function noLocation() { $("#results").html("") $("#searchBtn").attr("disabled", false) $("#searchForm").append(" Location: <input type='text' id='location'>") }

$(document).ready(function() { if(navigator.geolocation == null) noLocation() else { $("#results").html("<i>Locating you...</i>") navigator.geolocation.getCurrentPosition(foundLocation, noLocation) }

$("#searchBtn").click(function() {
	$("#results").html("&lt;i&gt;Searching...&lt;/i&gt;")
	var theURL = "http://local.yahooapis.com/LocalSearchService/V3/localSearch?callback=?"
	var data = {
		appid:"5rJLaITV34GaU8t05tz.MIYQfRol9PBL51PyK3KAhmRiFa0FEAtvFyD36r4xTns_VRP1",
		output:"json",
		query:$("#term").val()
	}
	if(lat != "" && long != "") {
		data.latitude = lat
		data.longitude = long
	} else {
		data.location = $("#location").val()
	}

	$.getJSON(theURL,data, function(d,s) {
		var result = ""
		for(var i=0; i&lt;d.ResultSet.Result.length;i++) {
			var node = d.ResultSet.Result[i]
			result += "&lt;p&gt;&lt;b&gt;" + node.Title + "&lt;/b&gt;&lt;br/&gt;"
			result += "&lt;a href='" + node.ClickUrl + "'&gt;"+node.Url+"&lt;/a&gt;&lt;br/&gt;"
			result += node.Address + ", "+node.City+", "+node.State+"&lt;/p&gt;"
		}
		$("#results").html(result)
	})
})

})

</script>

Ok, there's a lot going on here. Let's focus first on the document.ready block. I begin by checking to see if the navigator.geolocation object exists. If it doesn't, it means we are on a browser where we can't get the user's location. That runs the noLocation function. It enables the search button for my form (which I disabled while I was working) and adds a field for the user's location.

If the geolocation object exists, we fire off the request. Now notice - if for some reason the lookup fails, we still run the noLocation function. So we've got support for both non-supported clients and the user saying no to the location request. (Or some other error happening.) If the location works right, we have access to the user's longitude and latitude. We store those values and enable the button. (Notice I made use of the results area to tell the user I was looking up his location.)

Ok, so the final bit of code handles the Yahoo API stuff. I've got a click event listener for the search button. It can tell if it currently knows the long/lat value and will use it if so. Otherwise it uses the freeform location field. I construct my data and fire it off to Yahoo. The result handler simply outputs the result.

You can demo this here: http://www.coldfusionjedi.com/demos/feb1210/test4b.cfm

I tested it in Chrome, my iPhone Simulator (which uses a California location) and my actual iPhone, and it seems to work well.

p.s. So why did I put the button outside of the form? Probably a dumb reason, but I had trouble getting jQuery to add my location field before the search button. When I did a prepend, it just didn't show up. When I append to the search term field, it didn't work. When I appended to the form tag - it worked perfectly - but added it after the search button. Probably something silly I did wrong there - but I went with a quick fix.

Raymond Camden's Picture

About Raymond Camden

Raymond is a senior developer evangelist for Adobe. He focuses on document services, JavaScript, and enterprise cat demos. If you like this article, please consider visiting my Amazon Wishlist or donating via PayPal to show your support. You can even buy me a coffee!

Lafayette, LA https://www.raymondcamden.com

Archived Comments

Comment 1 by Kit Brandner posted on 2/13/2010 at 4:40 AM

Great example... for the jQuery thing, I think insertAfter() would work:

$("Location: <input type='text' />").insertAfter("#term")

Or insertBefore() the searchButton...

Comment 2 by Scott P posted on 2/13/2010 at 5:17 AM

To add support for android - add this at top:

<script type="text/javascript" src="http://code.google.com/apis..."></script>

Then make this change to the javascript:

$(document).ready(function() {
     if (window.google && google.gears){
     $("#results").html("<i>Locating you...</i>")
        gps = google.gears.factory.create('beta.geolocation');
            gps.getCurrentPosition(function (position){
           foundLocation(position);
            })
}

else {
if (navigator.geolocation == null)
noLocation()
else {
$("#results").html("<i>Locating you...</i>")
navigator.geolocation.getCurrentPosition(foundLocation, noLocation)
}
}

I sent Ray the file if the comments don't handle this.

Comment 3 by Adam posted on 2/13/2010 at 6:34 AM

^Scott P - hmm, interesting, doesn't look like Ray's added that code yet but on my Android it still ask's if I want to allow my location to be used, how's that working then? (No results are returned, but then even if I try it in a browser and enter my UK lat&long I get NY pizza results, so I'm guessing something else may be up)

Comment 4 by Raymond Camden posted on 2/13/2010 at 7:08 AM

@Kit: I'll try that next time. I knew there was a way.

@ScottP: Interesting. Query - why "window.google" and "google.gears"? Could you shorten it to window.google.gears != null or some such?

Comment 5 by Adam posted on 2/13/2010 at 7:12 AM

Just did a quick Google and found these jQuery plugins...

http://code.google.com/p/jq...
http://github.com/fabiant7t...

...both of which seem to also work fine on my Android without any specific google code being called or tested for, so looks like navigator.geolocation is compatible with both iPhone & Android (anyone confirm?)

Comment 6 by Raymond Camden posted on 2/13/2010 at 7:19 AM

Is there an Android simulator?

Btw - dumb question - but "Android" is a generic term, right? For a bunch of phones? Like the new Nexus One?

Comment 7 by Scott P posted on 2/13/2010 at 7:20 AM

@adam - no clue, mine didn't work until I added that. I'm on stock droid eris.

@ray http://developer.android.co...

Comment 8 by Scott P posted on 2/13/2010 at 7:24 AM

ray - the sdk is here:
http://developer.android.co...

Android is the operating system, several phones run it.
http://en.wikipedia.org/wik...

Comment 9 by Adam posted on 2/13/2010 at 7:27 AM

@Ray - as Scott linked to, grab the SDK (which uses Eclipse so you should feel fairly at home) and the emulator comes with it. And yeah Android is Googles mobile OS, so Nexus 1, bunch of recent HTC phones, upcoming Dell Mini 5 etc... many more to come this year.

@Scott - I'm on a G2 with a hacked 2.1 rom, so maybe it's new in the latest updates?

Comment 10 by Adam posted on 2/13/2010 at 7:30 AM

ahh, just noticed on the wikipedia page, 2.1 brought 'New browser UI and HTML5 support' ... that may be it.
(sorry to hijack your iPhone thread Ray :)

Comment 11 by Scott P posted on 2/13/2010 at 7:31 AM

yeah - iPhone is dead platform.

Comment 12 by aaron posted on 2/13/2010 at 11:34 AM

Try using jQuery's before() and after() instead of append() or prepend() so you can have your button inside of the form.

Comment 13 by Roverwolf posted on 2/13/2010 at 11:14 PM

If one uses this type of thing then it is usually nice to allow the user a chance to correct the location.

My iPod Touch seems to claim that it is in Washington DC when I am actually on the west coast.

Comment 14 by jeremy posted on 2/13/2010 at 11:41 PM

This was very helpful. Exactly what I needed.

Comment 15 by Raymond Camden posted on 2/13/2010 at 11:44 PM

@David: Yeah, good point.

Comment 16 by Ben Nadel posted on 2/15/2010 at 9:56 PM

That is very cool.

Comment 17 by Henry Cox posted on 3/30/2010 at 9:31 PM

Hi Ray,
Maybe I am missing something here, but, with I assume developers aiming for compatibility across all OS's don't most mobile devices support ECMAScript X. Is this above, with the additional comments, intended because these mobile devices don't support the ECMAScript standard, i.e., javascript Location Object. Thanks
Henry

Comment 18 by Raymond Camden posted on 3/30/2010 at 9:59 PM

I'm afraid I don't get what you are saying. Do you have a URL for the JS Location object? I'm only aware of document.location.

Comment 19 by Henry Cox posted on 3/30/2010 at 10:06 PM

Sorry about that. Don't all(or most current) mobile devices, that are equipped with Browsers, support javascript, therefore, the location can be determined through javascript's Location object and the device's hardware?
Thanks

Comment 20 by Raymond Camden posted on 3/30/2010 at 10:12 PM

What Location object though? That's the question I'm asking. I know of document.location, which is the URL object, but what do you mean? A URL reference would be handy.

Comment 21 by Jon Hayes posted on 6/9/2010 at 8:56 AM

Hi Ray, Banging my head on a table.....
In my hack of this script I am trying to send the
data.latitude = lat
data.longitude = long
to a cfc to set client.latitude in order to locate a user on a map as per Adam Tuttles solution for setting client variables on http://stackoverflow.com/qu...

Please please with candy on top can you help me figure out how to send the location data to my ClientFacade.cfc so I can pass the location data around my app! Thanks in advance...

Comment 22 by Raymond Camden posted on 6/9/2010 at 4:21 PM

Once you have the long/lat, you simply make the Ajax request. Look at his setValue.click function. Notice the $.getJSON function. That performs the Ajax request. Just use that portion.

Comment 23 by Jon Hayes posted on 6/10/2010 at 6:57 AM

ack. still trying. the cfc setting is working... I just can't seem to see how to write the json my code is (using google gears for development purposes here - my iphone 3g is definitely not that quick loading (I want a Droid... :) ):

var geo = google.gears.factory.create('beta.geolocation');
var latitude = {"mylatobject": function updatePosition(position) {
(position.latitude);
}
};

$.getJSON(
'clientFacade.cfc',
{
method:"set",
returnFormat:"json",
name:"foo",
"val":valu,
"mylat":latitude
},

basically my results are always 'undefined'... :(

Comment 24 by Raymond Camden posted on 6/10/2010 at 6:59 AM

Can you show us the entire code - or point us to the url?

Comment 25 by Jon Hayes posted on 6/10/2010 at 7:20 AM

The blog keeps flagging me as spam when I try to paste the code so I replied to your comments notification email address

http://www.environmental.ly...

Comment 26 by Raymond Camden posted on 6/10/2010 at 4:54 PM

Wow - your code is seriously messed up. :) I see the JS, then I see a copy of it outside of a script block (well there is a closing script block). Did you mispaste something? Also, I never saw my Long/Lat. Job one is to ensure that part works -then look into making it set and getting get to work.