Javascript 在自动完成选择时解析 Google 地图中的 address_components

声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow 原文地址: http://stackoverflow.com/questions/8082405/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me): StackOverFlow

提示:将鼠标放在中文语句上可以显示对应的英文。显示中英文
时间:2020-08-24 04:39:55  来源:igfitidea点击:

Parsing address_components in Google Maps upon autocomplete select

javascriptjquerygoogle-mapsgoogle-maps-api-3

提问by Victor

I have the following code to parse the countrywhen the autocomplete list is selected:

我有以下代码来解析country选择自动完成列表的时间:

$('#spot_address').autocomplete({
  // This bit uses the geocoder to fetch address values
  source: function(request, response) {
    geocoder.geocode( {'address': request.term }, function(results, status) {
      // Get address_components
      for (var i = 0; i < results[0].address_components.length; i++)
      {
        var addr = results[0].address_components[i];
        var getCountry;
        if (addr.types[0] == 'country') 
          getCountry = addr.long_name;
      }
      response($.map(results, function(item) {
        return {
          label: item.formatted_address,
          value: item.formatted_address,
          latitude: item.geometry.location.lat(),
          longitude: item.geometry.location.lng(),
          country: getCountry
        }
      }));
    })
  },

  // This bit is executed upon selection of an address
  select: function(event, ui) {
    // Get values
    $('#spot_country').val(ui.item.country);
    $('#spot_lat').val(ui.item.latitude);
    $('#spot_lng').val(ui.item.longitude);
    var location = new google.maps.LatLng(ui.item.latitude, ui.item.longitude);
    marker.setPosition(location);
    map.setCenter(location);
  },

  // Changes the current marker when autocomplete dropdown list is focused
  focus: function(event, ui) {
    var location = new google.maps.LatLng(ui.item.latitude, ui.item.longitude);
    marker.setPosition(location);
    map.setCenter(location);
  }
});

However, the code above doesn't work, and when the country is parsed, only the first result of the autocomplete is parsed no matter what, which is significant with the array results[0]because it only fetches the first result.

但是,上面的代码不起作用,并且在解析国家/地区时,无论如何都只解析自动完成的第一个结果,这对数组很重要,results[0]因为它只获取第一个结果。

I tried to move it to the selectfunction, but uiin selectonly contains formatted_address, longitudeand latitude, but not the address_components.

我试图把它移动到select的功能,但uiselect只包含formatted_addresslongitudelatitude,但不是address_components

What must I do to send the correct countrywhen the autocomplete list item is selected?

country选择自动完成列表项时,我必须做什么才能发送正确的信息?

Many thanks.

非常感谢。

采纳答案by Victor

Below is the full working code:

以下是完整的工作代码:

$('#spot_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) {
          // Get address_components
          for (var i = 0; i < item.address_components.length; i++)
          {
            var addr = item.address_components[i];
            var getCountry;
            if (addr.types[0] == 'country') 
              getCountry = addr.long_name;
          }
        return {
          label: item.formatted_address,
          value: item.formatted_address,
          latitude: item.geometry.location.lat(),
          longitude: item.geometry.location.lng(),
          country: getCountry
        }
      }));
    })
  },

  // This bit is executed upon selection of an address
  select: function(event, ui) {
    // Get values
    $('#spot_country').val(ui.item.country);
    $('#spot_lat').val(ui.item.latitude);
    $('#spot_lng').val(ui.item.longitude);
    var location = new google.maps.LatLng(ui.item.latitude, ui.item.longitude);
    marker.setPosition(location);
    map.setCenter(location);
  },

  // Changes the current marker when autocomplete dropdown list is focused
  focus: function(event, ui) {
    var location = new google.maps.LatLng(ui.item.latitude, ui.item.longitude);
    marker.setPosition(location);
    map.setCenter(location);
  }
});

回答by William Entriken

General solution:

一般解决方案:

var address_components = results[0].address_components;
var components={}; 
jQuery.each(address_components, function(k,v1) {jQuery.each(v1.types, function(k2, v2){components[v2]=v1.long_name});});

Now your componentslooks like this:

现在你components看起来像这样:

street_number: "1100", 
route: "E Hector St", 
locality: "Conshohocken", 
political: "United States", 
administrative_area_level_3: "Whitemarsh"…
administrative_area_level_1: "Pennsylvania"
administrative_area_level_2: "Montgomery"
administrative_area_level_3: "Whitemarsh"
country: "United States"
locality: "Conshohocken"
political: "United States"
postal_code: "19428"
route: "E Hector St"
street_number: "1100"

Which you can query like this:

您可以这样查询:

components.country

回答by Alex Cheremisin

Here is my solution in typescript

这是我在打字稿中的解决方案

interface AddressComponent {
  long_name: string;
  short_name: string;
  types: Array<string>;
}

interface Address {
  street_number?: string;
  street_name?: string;
  city?: string;
  state?: string;
  country?: string;
  postal_code?: string;
}

export class GoogleAddressParser {
  private address: Address = {};

  constructor(private address_components: Array<AddressComponent>) {
    this.parseAddress();
  }

  private parseAddress() {
    if (!Array.isArray(this.address_components)) {
      throw Error('Address Components is not an array');
    }

    if (!this.address_components.length) {
      throw Error('Address Components is empty');
    }

    for (let i = 0; i < this.address_components.length; i++) {
      const component: AddressComponent = this.address_components[i];

      if (this.isStreetNumber(component)) {
        this.address.street_number = component.long_name;
      }

      if (this.isStreetName(component)) {
        this.address.street_name = component.long_name;
      }

      if (this.isCity(component)) {
        this.address.city = component.long_name;
      }

      if (this.isCountry(component)) {
        this.address.country = component.long_name;
      }

      if  (this.isState(component)) {
        this.address.state = component.long_name;
      }

      if (this.isPostalCode(component)) {
        this.address.postal_code = component.long_name;
      }
    }
  }

  private isStreetNumber(component: AddressComponent): boolean {
    return component.types.includes('street_number');
  }

  private isStreetName(component: AddressComponent): boolean {
    return component.types.includes('route');
  }

  private isCity(component): boolean {
    return component.types.includes('locality');
  }

  private isState(component): boolean {
    return component.types.includes('administrative_area_level_1');
  }

  private isCountry(component): boolean {
    return component.types.includes('country');
  }

  private isPostalCode(component): boolean {
    return component.types.includes('postal_code');
  }

  result(): Address {
    return this.address;
  }
}

Usage:

用法:

const address = new GoogleAddressParser(results[0].address_components).result();

回答by ChrisRich

Elaborating on @Full Decent's answer here a version for lodash:

详细阐述@Full Decent 的回答,这里是 lodash 的一个版本:

_.each(address_components, function(k, v1) {
    _.each(address_components[v1].types, function(k2, v2){
        components[address_components[v1].types[v2]] = address_components[v1].long_name
    });
});

回答by Ahmed Ali Thabet

Here I made my own solution, as I wanted to get the city name and there may be more than one format for this, for example, the city name in some regions can be under the name of

这里我自己做了一个解决方案,因为我想获取城市名称,并且可能有不止一种格式,例如,某些地区的城市名称可以在以下名称下

 (locality, sublocality , sublocality_level_1, sublocality_level_2, sublocality_level_3
 or sublocality_level_4)

so I made this function

所以我做了这个功能

getAddressObject(address_components) {
  var ShouldBeComponent = {
    home: ["street_number"],
    postal_code: ["postal_code"],
    street: ["street_address", "route"],
    region: [
      "administrative_area_level_1",
      "administrative_area_level_2",
      "administrative_area_level_3",
      "administrative_area_level_4",
      "administrative_area_level_5"
    ],
    city: [
      "locality",
      "sublocality",
      "sublocality_level_1",
      "sublocality_level_2",
      "sublocality_level_3",
      "sublocality_level_4"
    ],
    country: ["country"]
  };

  var address = {
    home: "",
    postal_code: "",
    street: "",
    region: "",
    city: "",
    country: ""
  };
  address_components.forEach(component => {
    for (var shouldBe in ShouldBeComponent) {
      if (ShouldBeComponent[shouldBe].indexOf(component.types[0]) !== -1) {
        address[shouldBe] = component.long_name;
      }
    }
  });
  console.log(address);
  return address;
}

回答by Yom S.

Here's an ES6 and jQuery-less solution (based on William Entriken's post), making use of the native reducefunction and destructuring assignmentsyntax to unpack properties from objects, into distinct variables:

这是一个 ES6 和 jQuery-less 解决方案(基于William Entriken 的帖子),利用本机reduce函数和解构赋值语法将对象的属性解包为不同的变量:

const address = address_components.reduce((seed, { long_name, types }) => {
  types.forEach(t => {
    seed[t] = long_name;
  });

  return seed;
}, {});

Or, the one-liner version (for what it's worth):

或者,单线版本(物有所值):

const address = address_components.reduce((seed, { long_name, types }) => (types.forEach(t => seed[t] = long_name), seed), {});

Which you can then use like:

然后你可以使用它:

address.street_number
address.city

回答by LeoLozes

In an AngularJS controller, it could be like this:

在 AngularJS 控制器中,它可能是这样的:

function NewController() {
  var vm = this;

  vm.address = null;
  vm.placeService  = null;

  activate();

  function activate() {
    vm.placeService = new google.maps.places.PlacesService(document.getElementById("map"));
  }

  function getAddressComponent(address, component, type) {
    var element = null;
    angular.forEach(address.address_components, function (address_component) {
      if (address_component.types[0] == component) {
        element = (type == 'short') ? address_component.short_name : address_component.long_name;
      }
    });

    return element;
  }

  function getAddressDetail(addressId) {
    var request = {
      placeId: addressId
    };

    vm.placeService.getDetails(request, function(place, status) {
      if (status == google.maps.places.PlacesServiceStatus.OK) {
        vm.address = {
          countryCode: getAddressComponent(place, 'country', 'short'),
          countryName: getAddressComponent(place, 'country', 'long'),
          cityCode: getAddressComponent(place, 'locality', 'short'),
          cityName: getAddressComponent(place, 'locality', 'long'),
          postalCode: getAddressComponent(place, 'postal_code', 'short'),
          streetNumber: getAddressComponent(place, 'street_number', 'short')
        };
        console.log(vm.address);
      }
    });
  }
}

回答by Noel McKeown

This worked for me, in AngularJS;

这对我有用,在 AngularJS 中;

// Function converts GPS co-ordinates to a locality name
function showLocation(LatLng) {
    geocoder.geocode({'latLng': LatLng}, function (results, status) {
        if (status == google.maps.GeocoderStatus.OK) {
            console.log(results[0]);
            var myLocation;

            for (var i = 0; i < results[0].address_components.length; i++) {
                var addr = results[0].address_components[i];
                var getCountry;
                var getAdministrative;
                var getLocality;

                if (addr.types[0] == 'locality') {
                    getLocality = addr.long_name;
                    console.log(getLocality);
                    myLocation = getLocality+ ', ';
                }
                 if (addr.types[0] == 'administrative_area_level_1') {
                    getAdministrative = addr.long_name;
                    console.log(getAdministrative);
                    myLocation += getAdministrative + ', ';
                } 
                if (addr.types[0] == 'country') {
                    getCountry = addr.long_name;
                    console.log(getCountry);
                    myLocation += getCountry;
                }                             
            }
            $scope.locality = myLocation;
            console.log(myLocation);
        }
    })
};

回答by stephen.hanson

I've been using the following approach:

我一直在使用以下方法:

var city = getAddressComponent(place, 'locality', 'long_name');
var state = getAddressComponent(place, 'administrative_area_level_1', 'short_name');
var postalCode = getAddressComponent(place, 'postal_code', 'short_name');
var country = getAddressComponent(place, 'country', 'long_name');

function getAddressComponent(place, componentName, property) {
  var comps = place.address_components.filter(function(component) {
    return component.types.indexOf(componentName) !== -1;
  });

  if(comps && comps.length && comps[0] && comps[0][property]) {
    return comps[0][property];
  } else {
    return null;
  }
}

回答by user3795286

Country is always last in array that is returned from Geocoder.

国家/地区始终位于从 Geocoder 返回的数组中的最后。

Here is my solution -

这是我的解决方案 -

 geocoder.geocode( {'address': request.term }, function(results, status) {
   var location_country =
   results[0].address_components[results[0].address_components.length - 1].long_name;
});

Hope this helps.

希望这可以帮助。