13

Currenty, I'm using the following code to get the country, postal code, locality and sub-locality:

var country, postal_code, locality, sublocality;
for (i = 0; i < results[0].address_components.length; ++i)
{
    for (j = 0; j < results[0].address_components[i].types.length; ++j)
    {
        if (!country && results[0].address_components[i].types[j] == "country")
            country = results[0].address_components[i].long_name;
        else if (!postal_code && results[0].address_components[i].types[j] == "postal_code")
            postal_code = results[0].address_components[i].long_name;
        else if (!locality && results[0].address_components[i].types[j] == "locality")
            locality = results[0].address_components[i].long_name;
        else if (!sublocality && results[0].address_components[i].types[j] == "sublocality")
            sublocality = results[0].address_components[i].long_name;
    }
}

That's unsatisfactory. Is there any other way to achieve the same result?

0xbadf00d
  • 17,405
  • 15
  • 67
  • 107

9 Answers9

20

You could use the following function to extract any address component:

function extractFromAdress(components, type){
    for (var i=0; i<components.length; i++)
        for (var j=0; j<components[i].types.length; j++)
            if (components[i].types[j]==type) return components[i].long_name;
    return "";
}

To extract the info you call:

var postCode = extractFromAdress(results[0].address_components, "postal_code");
var street = extractFromAdress(results[0].address_components, "route");
var town = extractFromAdress(results[0].address_components, "locality");
var country = extractFromAdress(results[0].address_components, "country");

etc...

Johann
  • 12,158
  • 11
  • 62
  • 89
  • locality and route no longer works, do you have a solution? – rafcastro77 Nov 06 '18 at 15:36
  • Thank you for the solution, i've revised it and worked for me. this.editedItem.Province = this.extractFromAdress(data.results[0].address_components, "administrative_area_level_1"); this.editedItem.District = this.extractFromAdress(data.results[0].address_components, "administrative_area_level_2"); this.editedItem.Neighborhood = this.extractFromAdress(data.results[0].address_components, "administrative_area_level_4"); – Aurora Sep 05 '21 at 18:06
18

My one-liner using a functional approach and map, filter, and ES2015:

/**
 * Get the value for a given key in address_components
 * 
 * @param {Array} components address_components returned from Google maps autocomplete
 * @param type key for desired address component
 * @returns {String} value, if found, for given type (key)
 */
function extractFromAddress(components, type) {
    return components.filter((component) => component.types.indexOf(type) === 0).map((item) => item.long_name).pop() || null;
}

Usage:

const place = autocomplete.getPlace();
const address_components = place["address_components"] || [];

const postal_code = extractFromAddress(address_components, "postal_code");
Teh
  • 2,767
  • 2
  • 15
  • 16
user1429980
  • 6,872
  • 2
  • 43
  • 53
9

You can shorten it to

var country, postal_code, locality, sublocality;
for (i = 0; i < results[0].address_components.length; ++i) {
    var component = results[0].address_components[i];
    if (!sublocality && component.types.indexOf("sublocality") > -1)
        sublocality = component.long_name;
    else if (!locality && component.types.indexOf("locality") > -1)
        locality = component.long_name;
    else if (!postal_code && component.types.indexOf("postal_code") > -1)
        postal_code = component.long_name;
    else if (!country && component.types.indexOf("country") > -1)
        country = component.long_name;
}

Or are you trying to get a better formatted result? Then please show us your query.

Bergi
  • 630,263
  • 148
  • 957
  • 1,375
  • No, I just need the specific components. – 0xbadf00d Nov 29 '11 at 16:22
  • Do I even need to check if the variables are undefined? With other words: Is it possible that there are multiple components in one result with equal types? – 0xbadf00d Nov 30 '11 at 05:58
  • I've no idea whether that happens or not, but checking for not falsy values saves us from searching for already found types and therefore should be a littlebit faster. – Bergi Nov 30 '11 at 07:44
3

I did it like this:

placeParser = function(place){
  result = {};
  for(var i = 0; i < place.address_components.length; i++){
    ac = place.address_components[i];
    result[ac.types[0]] = ac.long_name;
  }
  return result;
 };

then i just use

parsed = placeParser(place)
parsed.route
bart
  • 14,958
  • 21
  • 75
  • 105
stef
  • 525
  • 6
  • 14
2

I really believe that user1429980 answer above deserves more recognition. It works really well. My answer is based on his function. I've added a few examples to better illustrate how to search the JSON object using the code user1429980 provided:

//searches object for a given key and returns the key's value

extractFromObject (object, key) { return object.filter((component) => component.types.indexOf(key) === 0).map((item)=>item.long_name).pop() || null; }


Example 1: Google's reverseGeocode API with longitude and latitude set at 43.6532,79.3832 (Toronto, Ontario, Canada):

var jsonData = {} //object contains data returned from reverseGeocode API

var city = extractFromObject(jsonData.json.results[0].address_components, 'locality');

console.log(city); //Output is Toronto


Example 2: Google's Places API with place ID set to ChIJE9on3F3HwoAR9AhGJW_fL-I (Los Angeles, CA, USA):

var jsonData = {} //object contains data returned from Google's Places API

var city = extractFromObject(jsonData.json.result.address_components, 'locality');

console.log(city); //Output is Los Angeles

Stranger26
  • 658
  • 5
  • 11
2

Using lodash

const result = _.chain(json.results[0].address_components)
  .keyBy('types[0]')
  .mapValues('short_name')
  .value()
James
  • 460
  • 2
  • 8
  • 15
1

Visitors using underscore.js can easily convert the address_components array in the geocode response into an object literal:

var obj = _.object( 
    _.map(results[0].address_components, function(c){ 
        return  [c.types[0], c.short_name] 
    })
);
Jordan Arsenault
  • 7,100
  • 8
  • 53
  • 96
0

I made function before that extracts a list of values given a list of place types:

const getValue = function(data, types=[]){
/* used by results taken from Geocoder.geocode api */
const values = data.reduce((values, address) => {
    return address.address_components.reduce((values2, component) => {
        if(component.types.reduce((result, type) => result || types.indexOf(type) > -1, false))
            values2.push(component.long_name);
        return values2
    }, []);

    if(buff.length)
        return [...values, ...buff];
    return values;
}, []).filter(
    (value, index, self) => {
        return self.indexOf(value) === index;
    }
);

}

Kyell
  • 621
  • 5
  • 9
0
if (typeof Object.keys == 'function')
    var length = function(x) { return Object.keys(x).length; };
else
    var length = function() {};

var location = {};      
for (i = 0; i < results[0].address_components.length; ++i)
{
    var component = results[0].address_components[i];
    if (!location.country && component.types.indexOf("country") > -1)
        location.country = component.long_name;
    else if (!location.postal_code && component.types.indexOf("postal_code") > -1)
        location.postal_code = component.long_name;
    else if (location.locality && component.types.indexOf("locality") > -1)
        location.locality = component.long_name;
    else if (location.sublocality && component.types.indexOf("sublocality") > -1)
        location.sublocality = component.long_name;

    // nothing will happen here if `Object.keys` isn't supported!
    if (length(location) == 4)
        break;
}

This is the most suitable solution for me. It may help someone too.

0xbadf00d
  • 17,405
  • 15
  • 67
  • 107