Parsing address_components in Google Maps upon autocomplete select
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 components
looks like this:
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
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();
Here's an ES6 and jQuery-less solution (based on William Entriken's post), making use of the native reduce
function and destructuring assignment syntax to unpack properties from objects, into distinct variables:
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