Poter cercare un indirizzo in google maps dalla nostra applicazione: semplicissimo con jQuery UI

Questo elemento dovrebbe fare parte di una imminente serie di articoli che farà la cronaca, a mo’ di tutorial, della relalizzazione di una applicazione cakephp completa in meno di un mese. Ma è troppo utile e semplice da implementare per non segnalarlo subito.

Contesto

In molte applicazioni può essere utile permettere agli utenti di inserire degli indirizzi, e mostrarli poi su una mappa google  (luoghi di svolgimento eventi, localizzare dove è stata scattata una foto e mille altri casi).

Mi è capitato di implementare una cosa simile con cakephp 1.2, usando l’ajax helper (con prototype), e geolocazione lato server. Alla fine ho trovato una buona soluzione, ma un po’ laboriosa e pesante.
E’ stato disarmante scoprire quanto fosse semplice e veloce realizzare una cosa simile (un caso un po’ più semplice, ma non di molto) con le API javascript di google maps e jQuery (con jQuery UI)

Situazione

Il problema maggiore che ho riscontrato in passato, nella soluzione “fatta a mano”, è stata l’ambiguità dei risultati. A volte la ricerca da risultati “errati” a seconda di come si scrive l’indirizzo (ad esempio, via “XXV Aprile” è diverso da “25 Aprile”  e da “venticinque aprile”), oppure per indirizzi dal nome molto simile.

Ora, i nostri utenti devono poter scrivere un indirizzo, ottenere suggerimenti, scegliere quello esatto direttamente nella forma data da google.
Una volta scelto ci serve la geolocazione dell’indirizzo, per ottenere i dati di latitudine e longitudine che salveremo direttamente nel database (per evitare di fare una nuova richiesta di geolocazione a google ogni volta che dobbiamo visualizzare i punti su una mappa, per un indirizzo di cui sappiamo già le coordinate geografiche).

Soluzione

Come fare? Semplice: c’è un tutorial già fatto, chiaro e funzionante.  (Guarda la demo!)

Faccio notare in particolare questa parte:

  1. $(function() {
  2. $("#address").autocomplete({
  3. //This bit uses the geocoder to fetch address values
  4. source: function(request, response) {
  5. geocoder.geocode( {'address': request.term }, function(results, status) {
  6. response($.map(results, function(item) {
  7. return {
  8. label: item.formatted_address,
  9. value: item.formatted_address,
  10. latitude: item.geometry.location.lat(),
  11. longitude: item.geometry.location.lng()
  12. }
  13. }));
  14. })
  15. },
  16. //This bit is executed upon selection of an address
  17. select: function(event, ui) {
  18. $("#latitude").val(ui.item.latitude);
  19. $("#longitude").val(ui.item.longitude);
  20. var location = new google.maps.LatLng(ui.item.latitude, ui.item.longitude);
  21. marker.setPosition(location);
  22. map.setCenter(location);
  23. }
  24. });

L’idea, semplice ed efficacissima, è basata su cosa passare all’autocomplete di  jQuery UI. Nota bene: per autocomplete non è una richiesta ajax vera e propria / che specifica il formato jsonp per interrogare una sorgente dati remota. Prende come sorgente direttamente quel che passa l’oggetto geocoder (geocoder = new google.maps.Geocoder();) che a sua volta fa la richiesta remota. Nei risultati c’è il campo “formatted_address”  che viene usato sia come etichetta che come valore per il menu a tendina dell’autocomplete.
La stessa richiesta ci permette di “mettere da parte” i valori di latitudine e longitudine, che usiamo per compilare i rispettivi campi nel form quando l’utente seleziona il rispettivo indirizzo.

Tutto qui, consiglio caldamente di leggersi il tutorial.

In Cake?

La bella notizia è che il codice è praticamente utilizzabile pari pari in una applicazione cakephp.
Praticamente si può prendere il codice di main.js dalla suddetta demo, salvarlo e includerlo nella view che ci interessa, e sostituire i selettori (#address, #lat e #lon) con gli id dei campi del nostro form, generati secondo le convenzioni di cakephp – ad esmepio MymodelAddress, MyModelLat, MyModelLon.

Trovo utile che i campi lat e lon siano, nel caso, compilabili anche a mano dall’utente, per quei casi in cui l’indirizzo non si trova su google maps, ma l’utente può ricavarne le coordinate (da google maps stessa o da altra fonte).

A proposito di coordinate: chi ha già letto il suddetto tutorial -o provato la demo-  avrà notato un simpatico bonus. Ovvero, utilizzando il reverse geocoding, quando la localizzazione dell’indirizzo non è precisissima, l’utente può semplicemente… trascinare il marker (l’iconcina sulla mappa) nel punto esatto per ottenere le coordinate (e l’indirizzo di quel punto secondo google)

Meglio di così..

Ma torniamo a cake: visto che le interazioni con i server di google sono tramite le sue API javascript, per la nostra applicazione è tutto lato client. Niente “ajax”, e, siccome non andiamo ad alterare il form o modificare campi nascosti, il tutto funziona perfettamente anche con il security component.

L’unica controindicazione può essere una certa “pesantezza” per l’eventuale alto numero di richieste tra la nostra applicazione e google maps; è quindi consigliabile usare un sistema di cache o limitarne l’uso per necessità specifiche ai soli utenti registrati.

Resta davedere cosa fare con gli indirizzi e le coordiante salvati, e come visualizzarli.. ma questo è un altro articolo.

  • stefano_ma

    “siccome non andiamo ad alterare il form o modificare campi nascosti, il tutto funziona perfettamente anche con il security component”

    A scanso di equivoci, -essendo tra l’altro una cosa non molto documentata- non è necessario che i campi latitudine e longitudine siano visibili e modificabili a mano; si possono anche trasformare in campi hidden, il cui valore verrà impostato così solo tramite javascript / jQuery.

    Però, in questo caso, siccome è proprio uno dei classici tipi di manipolazione da cui il security component dovrebbe proteggere, dobbiamo dirgli che è una manipolazione legittima (o, meglio, di ignorare quei campi)

    $this->Security->disabledFields = array(‘MyModel.Lat’,’MyModel.Lon’);

  • ste

    sembra che funzioni ancora..