I have a single text field on a user registration form for location.
I would essentially like this field to be validated against Google Maps (or equivilent) - only allowing valid locations to pass (ideally in a format something like Waterloo, London or London, England).
Requirements:
- As well as a location name, I also would like to return co-ordinates (lat, lng) for the center of that location (even if broad e.g. London, England) as I will be cross referencing this to serve relevent information to the user.
- An autocomplete list/ smart suggestion list based on valid locations (ideally just political locations - not street specific) as the user is typing in the field *(Edit: See below).
- Force the user to use a location from the autocomplete list.
Privilages permitting this field will be autofilled using HTML5 Geolocation API to get the user lat lng and then converted to a general location (i.e. general town - a bit like Tweetdeck for Chrome does when you hit 'Add your location').
The question is - what is the best way of going about this? What API's do I use? What sections of the API's do I use to achieve this?
*Edit: After experimenting with Google Maps API v3 geocoding it seems there is an issue regarding the results (a bug or by design I'm not sure - http://code.google.com/p/gmaps-api-issues/issues/detail?id=2042). For example if I type in Waterloo all I get is Waterloo, Canada. What about all the other Waterloos http://en.wikipedia.org/wiki/Waterloo? I want a list of X many (where X !== 1) for the user to select from. Ideally where I predefine X. Also if I type in 'L' to the form field I would like to see a list of relevent suggestions returned by order of most likely (perhaps influenced by the bias GeocodeRequest parameter) - so London, UK, Liverpool, UK, Leeds, UK etc etc. Instead I get Limburg, The Netherlands - 1 random result. WTF? What are the alternatives to doing this through Google Maps API?
*Update/Solution: Okay I've worked up a little something that uses geonames http://jsfiddle.net/ekzMN/95/. It's working pretty much okay, although I'm sure it can be massively improved on. You're all free to use this code as you wish. In my real world example I also add google geocode as a secondary source, as it's much smarter than geonames (i.e. if I type in a postcode, or a street address). This is dependent on intialising Geocoder:
// Get more specific results from Google geocode
geocoder.geocode( { 'address': request.term, 'region': 'GB' }, function(results, status) {
$.map(results, function(item) {
var ignore = ['route', 'country', 'natural_feature', 'intersection', 'premise', 'subpremise', 'airport', 'park', 'point_of_interest', 'establishment', 'transit_station'];
if (valid_location(item.types, ignore) == 1) {
var sublocality;
var locality;
var region;
var country;
$.each(item.address_components, function (i, data) {
if ($.inArray('sublocality', data.types) > -1) {
sublocality = data.long_name;
}
if ($.inArray('locality', data.types) > -1) {
if (typeof sublocality == 'undefined') {
sublocality = data.long_name;
}
}
if ($.inArray('administrative_area_level_2', data.types) > -1) {
locality = data.long_name;
}
if ($.inArray('administrative_area_level_1', data.types) > -1) {
region = data.long_name;
}
if ($.inArray('country', data.types) > -1) {
country = data.long_name;
}
});
if ((country != 'United Kingdom') || ($.inArray('administrative_area_level_1', item.types) == -1)) {
var location = format_location(sublocality, locality, region, country);
if (duplicate(matches, location) == 0) {
matches.push({
label: location,
value: location,
latitude: item.geometry.location.lat(),
longitude: item.geometry.location.lng()
});
}
}
}
});
// Update autocomplete
response(matches);
})
The combination of the two works well providing smart search and multiple suggestions. The one issue that's bugging me is when I use both sources (geonames & google geocode) then the input select range is very unreliable - sometimes it autofills, selects the additional section and then stays highlighted as it should, other times the blue highlight dissapears (although it acts as it's still there i.e. on keypress the selection dissapears), and other times the cursor goes straight to the end of the input. Some conflict with google maps I think, rather than multiple source issue, as this doesn't happen if I have two geonames sources instead?
Correct answer goes to anyone who can improve upon this!
Thanks