Sunday, September 16, 2012

Use Google Places Autocomplete with ZK Gmaps


Introduction

Places Autocomplete

From Google Maps JavaScript API v3 Reference:


The Places Autocomplete feature attaches to a text field on your web page, and monitors that field for character entries. As text is entered, Autocomplete returns Place predictions to the application in the form of a drop-down pick list.

When a user selects a Place from the list, information about the Place is returned to the Autocomplete object, and can be retrieved by your application.


ZK Gmaps

From ZK Component Reference:

A gmaps is a maps component that wraps the famous Google Maps service that you can control it and embedded it in your ZK web application page in pure Java.



This post is about how to use Google Maps Places Autocomplete with ZK Gmaps.

The Program

geo_autocomplete_test.zul

<zk xmlns:w="client">
    <!-- 
        Tested with ZK 6.0.2 and ZK-Gmaps 3.0.1
     -->
    <script type="text/javascript"><![CDATA[
        function init (wgt) {
            var loadAPI = setInterval(function() {
                // wait until places library ready
                if (window.google && window.google.maps && window.google.maps.places) {
                    var maps = google.maps,
                        complete = wgt._autocomplete = new google.maps.places.Autocomplete(wgt.getInputNode());

                    // listen to google's place_changed event
                    wgt._placeChanged = google.maps.event.addListener(wgt._autocomplete, 'place_changed', function () {
                        var p = complete.getPlace();
                        // triggered wrong
                        if (!p || !p.geometry)
                            return;
                        // prepare event data
                        var node = jq(wgt.getInputNode()),
                            location = p.geometry.location,
                            data = {place: p,
                                    lat: location.lat(),
                                    lng: location.lng()};
                        // fire onPlaceChanged event to CustomTextbox
                        wgt.fire('onPlaceChanged', data);
                    });
                    clearInterval(loadAPI);
                }
            }, 100);
        }
    ]]></script>
    <!-- This textbox uses the CustomTextbox which
        listen to onPlaceChanged event to receive the
        lat/lng from Google Maps Places Autocomplete
     -->
    <div style="margin: 20px;">
        <textbox use="test.geo.autocomplete.CustomTextbox">
            <attribute w:name="bind_"><![CDATA[
                function (a, b, c) {
                    // call original bind_ function
                    this.$bind_(a, b, c);
                    // attach to geo-autocomplete
                    init (this);
                }        
            ]]></attribute>
            <attribute name="onPlaceChanged"><![CDATA[
                import test.geo.autocomplete.PlaceChangedEvent;
                PlaceChangedEvent evt = (PlaceChangedEvent)event;
                gmap.setLat(evt.getLat());
                gmap.setLng(evt.getLng());
            ]]></attribute>
        </textbox>
        <!-- load Google Maps Places library
            by gmaps
         -->
        <gmaps id="gmap" width="500px" height="500px"
            libraries="geometry,places" />
    </div>
</zk>


We create a textbox with CustomTextbox class and use the input node of textbox to create google.maps.places.Autocomplete, fire onPlaceChanged event as need.

CustomTextbox.java

package test.geo.autocomplete;

import java.util.Map;

import org.zkoss.zk.ui.event.Events;
import org.zkoss.zul.Textbox;
/**
 * Tested with ZK 6.0.2 and ZK-Gmaps 3.0.1
 */
public class CustomTextbox extends Textbox {
    // listen to onPlaceChanged event with specific config
    static {
        addClientEvent(CustomTextbox.class, "onPlaceChanged",
                CE_IMPORTANT|CE_DUPLICATE_IGNORE);
    }
    public void service(org.zkoss.zk.au.AuRequest request, boolean everError) {
        final String cmd = request.getCommand();
        // handle event if it is onPlaceChanged event
        if ("onPlaceChanged".equals(cmd)) {
            // get data
            final Map data = request.getData();
            double lat = ((Double) data.get("lat")).doubleValue();
            double lng = ((Double) data.get("lng")).doubleValue();
            // create and post event
            PlaceChangedEvent evt = new PlaceChangedEvent(cmd, lat, lng);
            // post event to the custom textbox
            Events.postEvent(this, evt);
        } else {
            super.service(request, everError);
        }
    }
}


The CustomTextbox listen to onPlaceChanged event and post PlaceChangedEvent event as need.

PlaceChangedEvent.java


package test.geo.autocomplete;

import org.zkoss.zk.ui.event.Event;

/**
 * Tested with ZK 6.0.2 and ZK-Gmaps 3.0.1
 */
public class PlaceChangedEvent extends Event {

    private static final long serialVersionUID = 7538146314204639298L;
    double _lat;
    double _lng;
    public PlaceChangedEvent(String name, double lat, double lng) {
        super(name);
        _lat = lat;
        _lng = lng;
    }
    public Double getLat () {
        return _lat;
    }
    public Double getLng () {
        return _lng;
    }
}

Use this event to store the lat/lng info.

The Result
View demo on line
http://screencast.com/t/GtsCMZ4JiNeD


Reference
https://developers.google.com/maps/documentation/javascript/places


Download

Demo flash at github
https://github.com/benbai123/ZK_Practice/blob/master/Components/demos/addon/GEOAutocomplete.swf

Full project at github
https://github.com/benbai123/ZK_Practice/tree/master/Components/projects/Addon_Practice/GmapsPractice

No comments:

Post a Comment