【问题标题】:Parsing address_components in Google Maps upon autocomplete select在自动完成选择时解析 Google Maps 中的 address_components
【发布时间】:2011-12-26 07:31:13
【问题描述】:

我有以下代码解析自动完成列表时解析@ 987654321:

$('#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);
  }
});

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

我尝试将其移至select 函数,但select 中的ui 仅包含formatted_addresslongitudelatitude,但不包含address_components

在选择自动完成列表项时,我必须做的是什么来发送正确的country

非常感谢。

【问题讨论】:

    标签: javascript jquery google-maps google-maps-api-3


    【解决方案1】:

    无人问津的解决方案:@William Entriken 在 PHP 中的解决方案。

    
    $address_components = $geocodeResult[0]['address_components'];
    $components = [];
    foreach($address_components as $k1 => $v1) {
        foreach($v1['types'] as $k2 => $v2) {
            $components[$v2] = $v1['long_name'];
        }
    }
    
    dd($components);
    
    array:8 [
      "street_number" => "78"
      "route" => "New Oxford Street"
      "postal_town" => "London"
      "administrative_area_level_2" => "Greater London"
      "political" => "United Kingdom"
      "administrative_area_level_1" => "England"
      "country" => "United Kingdom"
      "postal_code" => "WC1A 1HB"
    ]
    

    【讨论】:

      【解决方案2】:
      function parseAddress(place) {
        const address = {}
      
        place.address_components.forEach(component => {
          let { long_name, types } = component
      
          if (types.includes('street_number')) {
            address.streetNumber = long_name
          } else if (types.includes('route')) {
            address.street = long_name
          } else if (types.includes('neighborhood')) {
            address.neighborhood = long_name
          } else if (types.includes('locality')) {
            address.city = long_name
          } else if (types.includes('administrative_area_level_2')) {
            address.county = long_name
          } else if (types.includes('administrative_area_level_1')) {
            address.state = long_name
          } else if (types.includes('country')) {
            address.country = long_name
          } else if (types.includes('postal_code')) {
            address.zip = long_name
          }
        })
      
        return address
      }
      

      【讨论】:

        【解决方案3】:

        下面是完整的工作代码:

        $('#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);
          }
        });
        

        【讨论】:

          【解决方案4】:

          这是一个 ES6 和 jQuery-less 解决方案(基于 William Entriken's post),利用原生的 reduce 函数和 destructuring assignment 语法将对象的属性解压缩到不同的变量中:

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

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

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

          然后你可以像这样使用:

          address.street_number
          address.city
          

          【讨论】:

            【解决方案5】:

            我们也可以用这个提取国家ID和州代码-

              const address_components = results[0].address_components;
              let components = {};
              address_components.map((value, index) => {
                value.types.map((value2, index2) => {
                  components[value2] = value.long_name;
                  if (value2==='country')
                    components.country_id = value.short_name;
                  if (value2==='administrative_area_level_1')
                    components.state_code = value.short_name;
                })
              })
            

            返回这个对象 -

            {
              administrative_area_level_1: "California"
              administrative_area_level_2: "Santa Clara County"
              country: "United States"
              country_id: "US"
              locality: "Mountain View"
              political: "United States"
              postal_code: "94043"
              route: "Amphitheatre Parkway"
              state_code: "CA"
              street_number: "1600"
            }
            

            【讨论】:

              【解决方案6】:

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

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

              所以我做了这个功能

              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;
              }
              

              【讨论】:

                【解决方案7】:

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

                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;
                  }
                }
                

                用法:

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

                【讨论】:

                  【解决方案8】:

                  一般解决方案:

                  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});});
                  

                  现在你的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"
                  

                  你可以这样查询:

                  components.country
                  

                  【讨论】:

                  • 不错 - 如果有人不知道第一行应该是 var address_components = results[0].address_components;
                  • +1,简单但在大多数情况下很有用。请注意,某些信息可能会在此过程中丢失(例如,当您有两个类型为 ['country', 'political'] 和 ['locality', 'political'] 的组件时,political 会被覆盖)
                  • 简单而精彩
                  • 很棒的sn-p。肯定会再次使用。这种模式有名字吗?
                  • @plushyObject 也许这就是访问者模式
                  【解决方案9】:

                  国家总是在从地理编码器返回的数组中的最后一个。

                  这是我的解决方案 -

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

                  希望这会有所帮助。

                  【讨论】:

                    【解决方案10】:

                    我一直在使用以下方法:

                    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;
                      }
                    }
                    

                    【讨论】:

                      【解决方案11】:

                      这里的功能与 Full Decent 的相同,但是是为 AngularJS 编写的:

                      function getAddressComponentByPlace(place) {
                          var components;
                      
                          components = {};
                      
                          angular.forEach(place.address_components, function(address_component) {
                              angular.forEach(address_component.types, function(type) {
                                  components[type] = address_component.long_name;
                              });
                          });
                      
                          return components;
                      }
                      

                      【讨论】:

                        【解决方案12】:

                        这对我有用,在 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);
                                }
                            })
                        };
                        

                        【讨论】:

                          【解决方案13】:

                          在这里详细阐述@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
                              });
                          });
                          

                          【讨论】:

                            【解决方案14】:

                            在 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);
                                  }
                                });
                              }
                            }
                            

                            【讨论】:

                              【解决方案15】:

                              我认为您需要将响应处理程序拆分为一个新函数。

                                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) { getDetails(item); }));
                                  })
                                },
                              

                              将其移到 .autocomplete 函数之外:

                              function getDetails(item) {
                                          return {
                                            label: item.formatted_address,
                                            value: item.formatted_address,
                                            latitude: item.geometry.location.lat(),
                                            longitude: item.geometry.location.lng(),
                                            country: getCountry
                                          }
                                        }
                              

                              【讨论】:

                                猜你喜欢
                                • 1970-01-01
                                • 2012-03-15
                                • 2017-09-06
                                • 1970-01-01
                                • 1970-01-01
                                • 2012-12-04
                                • 1970-01-01
                                • 2012-08-09
                                • 1970-01-01
                                相关资源
                                最近更新 更多