RSS Feed

Google Maps Suggest – Adress-Autovervollständigung mit Scriptaculous

Veröffentlich am Mittwoch, 7. Okt 2009 in Webentwicklung

Viele nutzen Autovervollständigungen auf ihrer Website. Es ist nicht nur eine sehr beeindruckende Technik, sondern zudem eine sehr nutzerfreundliche. Zusätzlich kann sie dazu dienen, dass in einem Formular möglichst gültige Werte gespeichert werden. Selbstverständlich müssen alle Daten serverseitig erneut überprüft werden.

Ich möchte heute zeigen, wie einfach es mit Scriptaculous möglich ist, eine Autovervollständigung mit Google-Maps-Adressen umzusetzen. Da man per AJAX nicht auf fremde Website einen AJAX-Request durchführen kann, müssen wir ein Skript als Schnittstelle zwischen Google Maps und unserer Website verwenden. Fangen wir also dieses Mal mit der serverseitigen Script an:

$json = json_decode(file_get_contents('http://maps.google.com/maps/geo?output=json&oe=utf8&sensor=false&hl=de&key=DEIN_GOOGLE_MAPS_API_KEY&q='.urlencode($_REQUEST['address'])));

echo '<ul>';
if(!empty($json->Placemark)){
	foreach($json->Placemark as $value){
		echo '<li>'.$value->address.'</li>';
	}
}
echo '</ul>';

Zuerst stellen wir eine Suchanfrage an Google Maps, wobei wir den zu suchenden Text einfach im Parameter “q” übergeben. Der Parameter “output” gibt hierbei das von Google Maps zurückgelieferte Format an. Ich habe hier JSON verwendet und wandle die Daten anschließend mit der json_decode() Funktion in ein Objekt um. Es kann aber genauso gut XML in Kombination mit einer XML Funktion sie simplexml_load_string() verwendet werden. Da JSON da kompaktere Format ist habe ich mich in diesem Beispiel dafür entschieden.

Ein weiterer interessanter Parameter ist “hl”, der die Sprache der Adressen angibt. Viele werden den Parameter auch von der Google Suche kenne. Hier werden die Adressen also in deutsch zurückgegeben. Mit Hilfe dieses einen Parameters könnt ihr also sehr schnell die Funktion auf andere Spracheversionen eurer Seite anpassen.

Damit ihr überhaupt eine Anfrage an Google Maps stellen dürft, benötigt ihr einen kostenlosen Google Maps API Key, den ihr an den “key” Parameter anhängen müsst (Danke an paddy, der mich auf das Fehlen des Keys hingewiesen hat).

Nachdem die Daten von Google Maps empfangen wurden und im Objekt vorhanden sind, geben wir sie an die JavaScript Funktion zurück. Dazu erzeugen wir einfach eine unsortierte Liste mit einem Eintrag pro gefundener Adresse.

Und jetzt kommen wir zum sehr umfangreichen clientseitigen Script. Dazu müssen wir erst einmal ein Formular mit einem Textfeld erzeugen. Außerdem benötigen wir ein DIV, in dem die Ergebnisse ausgegeben werden. Zu guter Letzt kommt dann noch das JavaScript, das den ganzen AJAX-Request und das Behandeln der Empfangenen Daten erledingen muss. Was aber sehr kompliziert klingt, ist recht kurz umgesetzt:

<input type="text" id="address" name="address" />
<div id="adresse_choices" class="autocomplete"></div>
<script type="text/javascript">
	new Ajax.Autocompleter('address', 'adresse_choices', 'get_addresses.php');
</script>

Die ganze Sache lässt sich mit einer einzigen Zeile JavaScript erledigen. Selbstverständlich müssen dazu noch im Kopfbereich die “prototype.js” sowie anschließend die “scriptaculous.js” eingebunden werden. Die Funktion Ajax.Autocompleter() gehört hierbei zum Funktionsumfang von Scriptaculous. Das fertige Resultat sieht dann wie folgt aus:

Google Maps Suggest

Die hier verwendete ABC-Straße ist kein Witz, sondern die Adresse von Google Deutschland. Eine weitere schöne Eigenschaft von Google Maps ist die automatische Rechtschreibkorrektur, die bei fehlehaften Eingaben durchgeführt wird. Selbst eine Eingabe wie “plazt der luftblöcke” führt trotzdem zu dem gewünschten Platz vor dem ehemaligen Berliner Flughafen. Um die Sache testen zu können, habe ich hier ein kleines Beipsiel erstellt, dass ihr euch auch gerne im Quellcode runterladen könnt. Ich habe zusätzlich noch eine Funktion verwendet, die den Suchbegriff hervorhebt:

Beispiel Download

Wir ihr also sehen könnt, ist es mit der Ajax.Autocompleter() Funktion und einem servreseitigen Skript sehr einfach möglich, auch Daten von anderen Seiten auszuliefern. Das dazu benötigte PHP Skript kann durch kleine Veränderungen an die entsprechende extrene Datenquelle und das zurückgelieferte Format angepasst werden. Die Funktion lässt sich aber natürlich auch genauso gut mit jQuery oder einem anderen Framework umsetzen. Dazu muss dann aber eventuell das zurückgelieferte Format des PHP Skript auch noch angepasst werden.

Ich hoffe das Beispiel hat euch gezeigt, wie vielfältig sich eine Autovervollständigung einsetzen lässt. Habt ihr auch schon einmal mit externen Daten gearbeitet? Oder habt ihr vielleicht eine Idee, konntet sie aber bisher nicht umsetzen? Über ein Kommentar dazu würde ich mich sehr freuen.

Hinterlasse einen Kommentar

  1. paddy sagt:

    it doesnt work :-( , the demo is not working?

  2. [...] Um die Ajax.Autocompleter Funktion nutzen zu können benötigt jedes Feld eine eindeutige ID. Nehmen wir also an, wir haben folgendes erstes Feld für unser Formular (hier ein Beispiel aus dem Artikel: Google Maps Suggest – Adress-Autovervollständigung mit Scriptaculous): [...]

  3. Steffan sagt:

    Hi,

    Nice script.

    Is there a possibilty to only show the result of the countries: Netherlands and Belgium?

    Thanks.

    • Bernhard sagt:

      Hi Steffan,

      that should be no problem. I you just query the data from Google and than filter the results by the “CountryNameCode” or “CountryName” field from the XML or JSON against the two countries. Depending on the language you use (the “hl” parameter) you have to use the correct spelling of the country name.

      I hope that gave you an idea on how to solve the problem. If you still have some question, don’t hestitate to leave another comment.

      • Gerald sagt:

        Hey!
        Can you please explain exactly how it works? Maybe with an Code sniplet? I don’t get it on my own :(

      • Bernhard sagt:

        I think I’ll write another post about that topic. But something like this should do the trick (untested):

        echo '<ul>';
        if(!empty($json->Placemark)){
           foreach($json->Placemark as $value){
        		if(in_array($value->AddressDetails->Country->CountryName, array('Netherlands', 'Belgium'))){
        			echo '<li>'.$value->address.'</li>';
        		}
           }
        }
        echo '</ul>';
        
        • Gerald sagt:

          Thank you very much! It works well.
          I wanna quote your first comment.
          “Depending on the language you use (the “hl” parameter) you have to use the correct spelling of the country name.”
          For example ‘array(‘Deutschland’)’

          Greetings

  4. Daniel sagt:

    hey
    ich komm mit den vielen skript nicht klar.
    ist es möglich nur ergebnis von deutschland auszugeben und 3 felder inputs dafür: Stadt, Strasse , plz . strasse sollte plz automatisch vervollständigen..hilfe

    • Bernhard sagt:

      Soweit ich das richtig verstehe möchtest du drei Eingabefelder anbeiten. Zuerst eines für die Stadt und anschließend eines für die Straße sowie für die PLZ. Der Benutzer füllt also zuerst das Feld Stadt aus und dann das Feld Straße. Wenn er dann auf Straße klickt soll das Feld PLZ automatisch gefüllt werden. Ist das soweit korrekt?

      Falls ja hier der Lösungsansatz. Für das Feld Straße nimmst du den Inhalt des Feldes und hängst den Text “, Deutschland” an. Das schickst du dann über die API an Google Maps. Wenn der Benutzer also z.B: “München” eingetippt hat, dann ergänzt du es zu “München, Deutschland”.

      Für die Straße sieht es dann ähnlich aus, wobei du hier die Werte für “Stadt” und “Straße” per AJAX an dein PHP-Skript übermittelst und diese Anschließend mit “Deutschland” zu einem Text verbindest. Wenn der Benutzer also z.B: “Maximilianstraße” angibt, verbindest du alle Parameter zu dem Text “Maximilianstraße, München, Deutschland”. Von der Google Maps API solltest du dann eine komplette Adresse inkl. PLZ bekommen, aus der du dann die PLZ auslesen und in das Feld PLZ per JavaScript einfügen kannst.

      Ich hoffe du hast ungefähr eine Ahnung, was ich meine und wie das Ganze gemacht werden kann. Vielleicht erstelle ich mal einen neuen Artikel zu dem Thema.

  5. Alex sagt:

    Thanks.
    This is just the script i was looking for.

    One question though: isn’t there a limit on the number of request per day? 2500 per 24hours per IPaddres, I think.
    This starts to count when request are made trought this ‘proxy’ script (get_addresses.php).
    Or isn’t that for these type of requests?

    • Bernhard sagt:

      There is nedeed a limit of 2,500 request pre day and IP as described here: http://code.google.com/apis/maps/faq.html#geocoder_limit. But as you cannot use the clients IP because of the same origin policy, you can’t avoid that. However, there are ways to do more request. You may buy a Google Maps API Premier account or you use different API that might offer more requests.

      Another way to cope with the limit is to cache request on your server in a database. Just use the form input string a the primary key and store the recieved XML string (or the serialized SimpleXML/JSON object) in the database. You can than query your DB first and afterwards the Google Maps API. That might also result in quicker responses as a query to your DB might be faster than a file_get_contents() to the Google Maps API.

  6. kiat sagt:

    Thanks for the tutorial, which is exactly what i am looking for. I have learned a few important lessons. THANKS!

  7. Geile Sache, werde ich mal für einen Magento Shop Checkout versuchen und passt sogar, dass Magento auf Prototype und Scriptaculous basiert.

  8. Martin sagt:

    Hallo,
    super Code danke!
    Eine Frage, wie kann ich idealer Weise im HTML-Bereich z.B. als Input-Feld jeweils Strasse, PLZ, Ort der “Ergebnis-XML” ausgeben?
    Möchte gerne dass der User nur in einem Suchfeld sucht und die gewählten Daten dann auf die Inputfelder verteilt werden. DANKE !!!!

  9. Martin sagt:

    Eine Frage noch, gibt es von google eine Api, welche auch noch zulässt, nach Unternehmen zu suchen?
    Bsp. Gebe ich ein Unternehmen und Ort in google maps bekomme ich den kompletten Adressdatensatz des Unternehmens :-) danke

  10. Horst sagt:

    Hallo,
    klasse Sache!
    Ich habe zwei Fragen.
    Darf man auch von einer komerziellen Webseite aus oder wenn ich eine komerzielle Softwareauf diese Googlefunktion zugreifen?

    Viele Grüße
    Horst

  11. iNett-works sagt:

    Vielen vielen Dank für diese Arbeit !
    Freundliche Grüsse, Uwe

  12. Steffi sagt:

    Super Skript!
    Ich habe nur ein kleines Problem, und zwar will ich Flughäfen suchen lassen. Bei “Flughafen Düsseldorf” funktioniert es einwandfrei, aber z.B. den Flughafen Münster/Osnabrück findet er nicht. Bei Eingabe von “FMO” bekomme ich das Ergebnis davon, aber wenn ich dann wieder genau dieses Ergebnis (Flughafen Münster/Osnabrück (FMO), 48268 Greven, Deutschland) eingebe, wird nichts gefunden. Das hat bestimmt nichts mit deinem Skript zu tun, aber hast du vielleicht eine Idee, wie man das lösen könnte?
    Viele Grüße von Steffi

    • Bernhard sagt:

      Hallo Steffi,
      das hat tatsächlich nichts mit meinem Skript zu tun. Mein Skript ist ja nur eine Schnittstelle zu den Ergebnissen von Google Maps und ich habe leider keinen Einfluss darauf, was Google liefert. Im Allgemeinen kann man aber sagen, dass es nur Straßennamen kennt, aber keine Gebäude, Einrichtungen, Institutionen oder Firmen an diesen Adressen. Eine Suche nach einem Flughafennamen wird also nicht immer funktionieren.

      • Steffi sagt:

        Ich habe noch mal ein bisschen rumprobiert, und es scheint ein Problem zu geben, wenn im Suchstring ein “/” vorkommt. Ich kriegs nur irgendwie nicht hin, den Character richtig zu escapen. Weißt du, wie das geht?

        Außerdem hab ich die zweite Version deines Skriptes laufen, und dort zeigt er nur das erste Suchergebnis. Ich habe dort noch ein

        foreach ($markers_dom->getElementsByTagName(‘Placemark’) as $oneplacemark) {

        eingefügt und schaue dann auf die jeweilige Nummer der items.

Hinterlasse einen Kommentieren

Impressum