Анализ адресов_компонентов в Картах Google при выборе автозаполнения
У меня есть следующий код для синтаксического анализа 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);
}
});
Однако приведенный выше код не работает, и когда страна анализируется, анализируется только первый результат автозаполнения, независимо от того, что значимо для массива results[0]
, потому что он извлекает только первый результат.
Я попытался переместить его в функцию select
, но ui
в select
содержит только formatted_address
, longitude
и latitude
, но не address_components
.
Что нужно сделать, чтобы отправить правильный country
, когда выбран элемент списка автозаполнения?
Большое спасибо.
Ответы
Ответ 1
Вот я снова отвечу на свой вопрос. Ниже приведен полный рабочий код:
$('#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);
}
});
Ответ 2
Общее решение:
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
Ответ 3
Разработка на @Full Достойный ответ здесь версия для 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
});
});
Ответ 4
В контроллере 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);
}
});
}
}
Ответ 5
Вот мое решение в машинописи
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();
Ответ 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
Это работало для меня, в 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);
}
})
};
Ответ 8
Я использовал следующий подход:
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;
}
}
Ответ 9
Я думаю, вам нужно разделить обработчик ответа на новую функцию.
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
}
}
Ответ 10
Вот такая же функция, как Full Decent's, но написана для 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;
}
Ответ 11
Страна всегда является последней в массиве, которая возвращается из Geocoder.
Вот мое решение -
geocoder.geocode( {'address': request.term }, function(results, status) {
var location_country =
results[0].address_components[results[0].address_components.length - 1].long_name;
});
Надеюсь, что это поможет.
Ответ 12
Мы также можем извлечь идентификатор страны и код штата с помощью этого -
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"
}
Ответ 13
Вот ES6 и JQuery менее раствор ( на основе William Entriken поста), что делает использование нативного reduce
функции и DESTRUCTURING назначения синтаксиса для распаковки свойств из объектов, на отдельные переменные:
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