Google Places Autocomplete suggestions with Unit N

2019-04-18 14:20发布

问题:

I am using Google places API to auto-complete addresses using javascript

When I type the unit number and street number of address in the input box it shows the results in suggestion drop-down but when I select the address the listener for action 'place_changed' event don't have any address with address_component with type 'subpremise' even the formatted_address property don't have the unit number in it.Though it does contain other details from 'street number','city','country' etc

For example : If I type "1403/648 Bourke Street" with a country restriction to Australia. It shows me 5 results in the dropdown with first one as "1403/648 Bourke street, Melbourne,Australia" but when I select this option all I get in the place_change event listener is "648 Bourke street, Melbourne, Australia"

This issue is intermittent though, it works for some unit addresses but fail for other.Any suggestion will be highly appreciated!!

回答1:

It seems to me like Google is validating that the address is real (well atleast real when they last updated their places database - I guess with government records). The problem is that subdivisions are happening all the time where new "subpremise" addresses are created, and a look up on these seems to be br0ken more often. It's strange that they allow a "non-valid" address as an autocomplete suggestion but then limit the result.

A look up on the Sydney address below will return "subpremise" and "street_number"

"9/321 Pitt Street, Sydney, New South Wales, Australia"

Where the Melbourne address below only gets as accurate as "route"

"2/321 Pitt Street, Brunswick, Victoria, Australia"

The biggest problem is that the result doesn't return the unit or street number anywhere in the reply.

I have hacked together the following JS to compare the user-entered address with the returned result. If the "numbers" are missing, they are added. You can customise as you need to fit with your code.

if (addressType == 'route') {
    var regex = RegExp('^(.*)'+GPLACESSTREET.split(' ',1)[0]), // get all the user entered values before a match with the first word from the Google result
        result = regex.exec(INPUTFEILD.value);

    if ( Array.isArray(result) ) {
        FULLSTREETADDRESS = result[1]+''+GPLACESSTREET; // add the street name to the user-entered unit & street number
    }
}


回答2:

The Places Autocomplete API is not designed to support 'subpremise' results. This was reported and answered some time ago in the public issue tracker at https://issuetracker.google.com/35830389

Australian addresses for subpremise results look "close enough" to those of street_address/premise results (they start with mostly digits). This is currently resulting in Place Autocomplete returning what may look like a subpremise result, however note that the type is still "route":

http://maps.googleapis.com/maps/api/place/autocomplete/json?input=9/321%20Pitt%20Street,%20Sydney

description: "9/321 Pitt Street, Sydney NSW, Australia",
place_id: "Eig5LzMyMSBQaXR0IFN0cmVldCwgU3lkbmV5IE5TVywgQXVzdHJhbGlh",
types: ["route","geocode",],

Place Details (and Geocoding) requests with this place_id will in fact find the correct subpremise result:

https://maps.googleapis.com/maps/api/place/details/json?placeid=Eig5LzMyMSBQaXR0IFN0cmVldCwgU3lkbmV5IE5TVywgQXVzdHJhbGlh

   "result" : {
      "address_components" : [
         {
            "long_name" : "9",
            "short_name" : "9",
            "types" : [ "subpremise" ]
         },
         {
            "long_name" : "321",
            "short_name" : "321",
            "types" : [ "street_number" ]
         },
      ...
      "formatted_address" : "9/321 Pitt St, Sydney NSW 2000, Australia",
      "types" : [ "subpremise" ],

However, this is not guaranteed to work for all subpremise queries, or even for this particular one in the long term.

A more reliable approach would be to use the Geocoding API to search for the prediction's "description":

https://maps.googleapis.com/maps/api/geocode/json?&address=9%2F321%20Pitt%20St%2C%20Sydney%20NSW%202000%2C%20Australia

   "results" : [
      {
         "address_components" : [
            {
               "long_name" : "9",
               "short_name" : "9",
               "types" : [ "subpremise" ]
            },
            {
               "long_name" : "321",
               "short_name" : "321",
               "types" : [ "street_number" ]
            },
            ...
         ],
         "formatted_address" : "9/321 Pitt St, Sydney NSW 2000, Australia",
         "place_id" : "Eik5LzMyMSBQaXR0IFN0LCBTeWRuZXkgTlNXIDIwMDAsIEF1c3RyYWxpYSIdGhsKFgoUChIJkyPU0z2uEmsR-pmiK6UvZUASATk",
         "types" : [ "subpremise" ]


回答3:

A slight modification from @MountainAsh's code:

if (addressType == 'route') {
  var regex = RegExp('^(.*?)'+GPLACESSTREET.split(' ',1)[0]), // get all the user entered values before a match with the first word from the Google result
  result = regex.exec(INPUTFEILD.value);

  if ( Array.isArray(result) ) {
    FULLSTREETADDRESS = result[1]+''+GPLACESSTREET; // add the street name to the user-entered unit & street number
  }
}

Notice the additional ? in RegExp, which makes the search non-greedy to cover cases where the Street Name starts with the same Suburb name (e.g. 123 Clayton Rd, Clayton).



回答4:

Google doesn't support it, but you cant stop customers doing it!

Here is a complete function inspired by @MountainAsh's & @Randell's code:

/* Add the unit number (+ fix the street number) if required.
 *
 * Idea from https://stackoverflow.com/questions/17936689/google-places-autocomplete-suggestions-with-unit-no-subpremise-is-not-coming-in
 *
 * Test cases:
 * 9/321 Pitt Street, Sydney, New South Wales, Australia <-- Google throws away the unit number
 * 2/321 Pitt Street, Brunswick, Victoria, Australia <-- Google says street number = 2
 * 1b/123 Clayton Road, Clayton, Victoria, Australia <-- Google says street number = 1
 */
function autofillUnitNumber(txtAutocomplete, txtUnitNumber, txtStreetNumber, txtStreetName) {
    var regex = RegExp("^(.*?)\/(.*?) " + txtStreetName.value); // get all the user entered values before a match with the street name; group #1 = unit number, group #2 = street number
    var results = regex.exec(txtAutocomplete.value);

    if (Array.isArray(results)) { // it was in unit number/street number format
        var unitNumber = results[1]; // group #1 
        var streetNumber = results[2]; // group #2

        txtUnitNumber.value = unitNumber;
        txtStreetNumber.value = streetNumber;
    }
}

Just call it after you have used Google autocomplete to autofill your other form fields eg:

autofillUnitNumber(
    document.getElementById("txtAutocomplete"),
    document.getElementById("txtUnitNumber"),
    document.getElementById("txtStreetNumber"),
    document.getElementById("txtStreetName"));