PROGRAMMING

Area-restricted place search using Google Maps SDK

Recently I’ve had a chance to implement a location search functionality for a food ordering website, similar to pyszne.pl. The main requirement was to allow the user to fill in his address and based on detected postal code, there would be an info displayed about shipping possibility and cost.

Location search

When we want to implement google maps-powered location search in our application, we have 2 components to choose: Autocomplete or SearchBox.

Autocomplete

When the user enters a search query in the input, it shows a dropdown list of results. You have a possibility to restrict the search to specific bounds, country or place type in the configuration.

Offers the same search capabilities, although it returns extended list of results - including places and suggestions. When it comes to restricting result list, you can only bias the search towards bounds. It means that places inside your bounds will be shown first, but you will get other results from all over the world as well.

Search restriction to specific bounds

Let’s say we want to limit the results to places in Krakow. Using default configuration, we would see locations from other cities.

Unbounded search

In this case we need to choose Autocomplete component, as it provides more restricted results.

In order to make it work as expected, we have to define two geo points:

  • South West
  • North East
const input = document.getElementById('location_search_input');
const autocomplete = new google.maps.places.Autocomplete(input, {
    bounds: new google.maps.LatLngBounds(
        new google.maps.LatLng(50.037885, 19.909570), // south-west
        new google.maps.LatLng(50.080456, 19.971009) // north-east
    ),
    strictBounds: true,
});

After refreshing the page, we can see results restricted to selected bounds.

Bounded search

Finding postal code

autocomplete.getPlace() method returns currently selected location and all its details:

{
   "address_components":[
      {
         "long_name":"77",
         "short_name":"77",
         "types":[
            "street_number"
         ]
      },
      {
         "long_name":"Wrocławska",
         "short_name":"Wrocławska",
         "types":[
            "route"
         ]
      },
      {
         "long_name":"Krowodrza",
         "short_name":"Krowodrza",
         "types":[
            "sublocality_level_1",
            "sublocality",
            "political"
         ]
      },
      {
         "long_name":"Kraków",
         "short_name":"Kraków",
         "types":[
            "locality",
            "political"
         ]
      },
      {
         "long_name":"Kraków",
         "short_name":"Kraków",
         "types":[
            "administrative_area_level_2",
            "political"
         ]
      },
      {
         "long_name":"małopolskie",
         "short_name":"małopolskie",
         "types":[
            "administrative_area_level_1",
            "political"
         ]
      },
      {
         "long_name":"Poland",
         "short_name":"PL",
         "types":[
            "country",
            "political"
         ]
      },
      {
         "long_name":"30-006",
         "short_name":"30-006",
         "types":[
            "postal_code"
         ]
      }
   ],
   "adr_address":"<span class=\"street-address\">Wrocławska 77</span>, <span class=\"postal-code\">30-006</span> <span class=\"locality\">Kraków</span>, <span class=\"country-name\">Poland</span>",
   "formatted_address":"Wrocławska 77, 30-006 Kraków, Poland",
   "geometry":{
      "location":{
         "lat":50.0800861,
         "lng":19.9201865
      },
      "viewport":{
         "south":50.07873711970851,
         "west":19.918837519708518,
         "north":50.0814350802915,
         "east":19.92153548029148
      }
   },
   "icon":"https://maps.gstatic.com/mapfiles/place_api/icons/geocode-71.png",
   "id":"c826b43cd35a2368444ff709ac0bbff224208090",
   "name":"Wrocławska 77",
   "place_id":"EiZXcm9jxYJhd3NrYSA3NywgMzAtMDA2IEtyYWvDs3csIFBvbHNrYQ",
   "reference":"CpQBhAAAABuX2U5Y9SttYnusgpsTUwAVRmyPfOfmc9uy4LybjBictxNW2mvJgEAlpBHSsvSyUjD0-mvSk9Q4CyDVqqvrEgQE1Hwiq3aOekjVvvYZNMksoJJG3AkzGaVZRTOZxMWgAeB5JiZdpTaRcTRfovEGkq0B8vlNML87MNnayQWZX2jIH7vdLuMQkSGqubUzWPj9uRIQnaF1I5WjpoCvi1jc_XvL5xoUJ_XgaAQ0iY_FtyN1ifYBbJEvyfo",
   "scope":"GOOGLE",
   "types":[
      "street_address"
   ],
   "url":"https://maps.google.com/?q=Wroc%C5%82awska+77,+30-006+Krak%C3%B3w,+Poland&ftid=0x47165bad5b8dbd0f:0x86b7975122e03dfd",
   "utc_offset":120,
   "vicinity":"Krowodrza",
   "html_attributions":[

   ]
}

The most interesting part of that JSON is the last object inside address_components array:

{
   "long_name":"30-006",
   "short_name":"30-006",
   "types":[
      "postal_code"
   ]
}

Autocomplete component emits some events we can listen on, one of them is place_changed, so the solution is to combine place_changed event listener and autocomplete.getPlace() method call:

autocomplete.addListener('place_changed', () => {
    const place = autocomplete.getPlace();
    const postalCodeAddressComponent = place.address_components.find(
        component => component.types.includes('postal_code')
    );
    if (postalCodeAddressComponent) {
        console.log(postalCodeAddressComponent.long_name);
    }
});

Tomasz Chojna

Software Developer @ Grand Parade (William Hill)