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:
- $(function() {
- $("#address").autocomplete({
- //This bit uses the geocoder to fetch address values
- source: function(request, response) {
- geocoder.geocode( {'address': request.term }, function(results, status) {
- response($.map(results, function(item) {
- return {
- label: item.formatted_address,
- value: item.formatted_address,
- latitude: item.geometry.location.lat(),
- longitude: item.geometry.location.lng()
- }
- }));
- })
- },
- //This bit is executed upon selection of an address
- select: function(event, ui) {
- $("#latitude").val(ui.item.latitude);
- $("#longitude").val(ui.item.longitude);
- var location = new google.maps.LatLng(ui.item.latitude, ui.item.longitude);
- marker.setPosition(location);
- map.setCenter(location);
- }
- });
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.