GeoNames Home | Postal Codes | Download / Webservice | About |
search

Address Autocomplete with JSON webservice


This service returns a list of placenames for a given postalcode. The result is using the JSON format to overcome the problems with loading xml data from an other server. It is thus possible to use the geonames server for this placename lookup within webpages served by your own server.

Parameters :
postalcode : full postal code
country : ISO 3166 country code
maxRows : the maximal numbers of rows returned, optional parameter with a default value of 10
callback : optional parameter to specifiy the name of the javascript function to be wrapped around the datastructure.

The webservice returns an array of postalcodes objects. The objects have the attributes : placeName,countryCode, postalcode.

Example url :
http://api.geonames.org/postalCodeLookupJSON?postalcode=6600&country=AT&username=demo


Lets look at an example :

Country
PostalCode / Place
Fill in the postalcode field with a valid and complete postal code and see how the place field gets automatically updated as soon as you leave the field. Or in case there are several different placenames using the same postalcode you will see a suggest box.
Try the postalcode 6600 for Austria to see the suggest box or 2161 for an immediate update.

code walk-through

Here you find a bare bones version of this example and an example displaying latitude and longitude. Feel free to include the code in your own website. (don't forget the link to www.geonames.org ;-)


The javascript file http://api.geonames.org/export/geonamesData.js?username=demo contains an array with all countries supported for this service and the country of the user's ip address. This file has to be downloaded from the geonames server, don't host it on your own server as it contains user specific data (user country).
<script type="text/javascript" src="http://api.geonames.org/export/geonamesData.js?username=demo"></script>


The javascript file jsr_class.js contains some helper methods for JSON. You can put this file on your own server.
<script type="text/javascript" src="/export/jsr_class.js"></script>



The css style used for the suggest box.
<style>
  #suggestBoxElement {border: 1px solid #8FABFF; visibility:hidden; text-align: left;  white-space: nowrap; background-color: #eeeeee;}
  .suggestions { font-size: 14;background-color: #eeeeee;  }
  .suggestionMouseOver { font-size: 14;background: #3333ff; color: white;  }
</style>



<script type="text/javascript" >
// postalcodes is filled by the JSON callback and used by the mouse event handlers of the suggest box
var postalcodes;

// this function will be called by our JSON callback
// the parameter jData will contain an array with postalcode objects
function getLocation(jData) {
  if (jData == null) {
    // There was a problem parsing search results
    return;
  }

  // save place array in 'postalcodes' to make it accessible from mouse event handlers
  postalcodes = jData.postalcodes;
    	
  if (postalcodes.length > 1) {
    // we got several places for the postalcode
    // make suggest box visible
    document.getElementById('suggestBoxElement').style.visibility = 'visible';
    var suggestBoxHTML  = '';
    // iterate over places and build suggest box content
    for (i=0;i< jData.postalcodes.length;i++) {
      // for every postalcode record we create a html div 
      // each div gets an id using the array index for later retrieval 
      // define mouse event handlers to highlight places on mouseover
      // and to select a place on click
      // all events receive the postalcode array index as input parameter
      suggestBoxHTML += "<div class='suggestions' id=pcId" + i + " onmousedown='suggestBoxMouseDown(" + i +")' onmouseover='suggestBoxMouseOver(" +  i +")' onmouseout='suggestBoxMouseOut(" + i +")'> " + postalcodes[i].countryCode + ' ' + postalcodes[i].postalcode + '    ' + postalcodes[i].placeName  +'</div>';
    }
    // display suggest box
    document.getElementById('suggestBoxElement').innerHTML = suggestBoxHTML;
  } else {
    if (postalcodes.length == 1) {
      // exactly one place for postalcode
      // directly fill the form, no suggest box required 
      var placeInput = document.getElementById("placeInput");
      placeInput.value = postalcodes[0].placeName;
    }
    closeSuggestBox();
  }
}


function closeSuggestBox() {
  document.getElementById('suggestBoxElement').innerHTML = '';
  document.getElementById('suggestBoxElement').style.visibility = 'hidden';
}


// remove highlight on mouse out event
function suggestBoxMouseOut(obj) {
  document.getElementById('pcId'+ obj).className = 'suggestions';
}

// the user has selected a place name from the suggest box
function suggestBoxMouseDown(obj) {
  closeSuggestBox();
  var placeInput = document.getElementById("placeInput");
  placeInput.value = postalcodes[obj].placeName;
}

// function to highlight places on mouse over event
function suggestBoxMouseOver(obj) {
  document.getElementById('pcId'+ obj).className = 'suggestionMouseOver';
}


// this function is called when the user leaves the postal code input field
// it call the geonames.org JSON webservice to fetch an array of places 
// for the given postal code 
function postalCodeLookup() {

  var country = document.getElementById("countrySelect").value;

  if (geonamesPostalCodeCountries.toString().search(country) == -1) {
     return; // selected country not supported by geonames
  }
  // display 'loading' in suggest box
  document.getElementById('suggestBoxElement').style.visibility = 'visible';
  document.getElementById('suggestBoxElement').innerHTML = '<small><i>loading ...</i></small>';

  var postalcode = document.getElementById("postalcodeInput").value;

  request = 'http://api.geonames.org/postalCodeLookupJSON?postalcode=' + postalcode  + '&country=' + country  + '&callback=getLocation&username=demo';

  // Create a new script object
  aObj = new JSONscriptRequest(request);
  // Build the script tag
  aObj.buildScriptTag();
  // Execute (add) the script tag
  aObj.addScriptTag();
}

// set the country of the user's ip (included in geonamesData.js) as selected country 
// in the country select box of the address form
function setDefaultCountry() {
  var countrySelect = document.getElementById("countrySelect");
  for (i=0;i< countrySelect.length;i++) {
    // the javascript geonamesData.js contains the countrycode
    // of the userIp in the variable 'geonamesUserIpCountryCode'
    if (countrySelect[i].value == geonamesUserIpCountryCode) {
      // set the country selectionfield
      countrySelect.selectedIndex = i;
    }
  }
}



We preselect the users home country when we load the page. (The method setDefaultCountry() is using geonamesData.js)
<body onload="setDefaultCountry();">

The postal code input field calls postalCodeLookup() as soon as the field is left by the user.
<input id="postalcodeInput" name="postalcode" onblur="postalCodeLookup();" size="10" type="text">

The place input field is placed inside a span element with relative position and z-index 24. Within the same span element we place another element serving as our suggest box. The suggest box element has absolute positioning (relative to its parent !) and z-index 25. The suggest box element is initialliy hidden (visibility: hidden) and will be made visible as soon as we are gooing to use it.
<span style="position: relative; z-index: 24;">
  <input id="placeInput"  name="place" size="30" onblur="closeSuggestBox();" type="text">
  <span style="position: absolute; top: 20px; left: 0px; z-index:25;visibility: hidden;" id="suggestBoxElement"></span>
</span>



Concluding remarks

Using the approach above you, you will run into a problem with IE if you have a form select below the suggest box. Explorer ALWAYS renders select elements above all other elements regardless of the z-layer. In this case you will have to hide the select element while the suggest box is displayed. Webreference.com has an article on this problem with Explorer.


Credits

This product includes GeoLite data created by MaxMind, available from http://www.maxmind.com/.