Recently I was faced with having to add a location search mechanism to our application. My given task was short and clear: “We need to enter a few chars here and see the list of matching locations there…” I nodded, made myself a cup of coffee, and started thinking about how I was going to do it.
It was easy to guess that the task itself could be split into two parts: to build a component with combo box behavior and to invent a geocoding service to search locations by the text entered in the combo box. Fortunately for me, we already have a flexible dhtmlxCombo component, so the first part didn’t require any work on my part. There is also a set of free online geocoding services on the internet, so I’ve chosen Google Maps API for the second part.
Step 1 – Prepare dhtmlxCombo
If by chance you aren’t familiar with the dhtmlxCombo component, it is a select-like control that can automatically fetch items when a user types it in. What’s more important, the standard behavior of finding items can be replaced with user-defined functions by attaching it to the onDynXLS event. The event handler receives text entered into the combo, and that’s what we need.
The “initCombo” function will be called after the page load.
First we create the combo box in HTML element with id=”comboID” and set its width to 200px. The next line adds autocomplete features to the combo. The first parameter enables them, and the next one sets up the URL of the page where to look for the results. Since a geoservice will be used instead, I just entered “http://”. The last parameter enables or disables caching. Google geocoder has its own cache, that’s why I disabled this one.
Finally, we attach the onDynamicLoad function to the onDynXLS event. The handler returns “false” in order to stop default search functionality.
Step 2 – Google Geocoder
Geocoding itself is a mechanism of converting geographical data (in our case, address) into geographical coordinates. Google’s GClientGeocoder class makes it possible to search locations by address and receive a collection of location objects as a result. Each of them contains coordinates and a proper location address- i.e., all the information we need. It’s free with just a few limitations. You’ll be prompted to enter a site name for which API will be used. For test purposes, “http://localhost” is good enough.
So briefly, here’s how it works. We create the GClientGeocoder class instance and call the getLocations method which needs only 2 parameters: the text to search location by and the reference to the function that receives the result.
Seems easy. Now we just need to bring it all together.
Step 3 – Getting Things to Work
Well, here’s the strategy: After dhtmlxCombo tries to fetch items the first time, GClientGeocoder is created, and all data requests are done through it. The geocoder callback function that receives locations becomes responsible for putting them into the combo. That’s it.
Some comments:
The “location”, returned by the geocoder, contains a collection of Placemark objects. Each of them represents one location. In the code above, coordinates of the location go to the combo item’s value. The address info goes to the item’s text. The black magicinvolves the section between and including the lines with “enableFilteringMode”.
We need these lines for a reason that is not obvious. When filtering mode is ON, any action that opens the combo causes the onDynXLS event to be fired. We need to open the combo, but we are already in an onDynXLS event. The easiest way to prevent universal chaos in this case is to disable filtering before opening the combo and then enabling it again after the combo is open.
Instead of Conclusion
With approximately 20 lines of JavaScript code, we’ve managed to create a tool that takes user input, asks Google the meaning of the input, and shows a list of locations with real coordinates that the user is probably interested in. Christopher Columbus would’ve killed for that. I spent a bit over an hour and got it for free :) Sometimes I really love my job.
Posted by Paul Smirnov