Retrieving Postal Code with Google Maps Javascript API V3 Reverse Geocode
Asked Answered
C

23

23

I'm trying to submit a query using the postal code to my DB whenever the googlemaps viewport center changes. I know that this can be done with reverse geocoding with something like:

google.maps.event.addListener(map, 'center_changed', function(){
newCenter();
});
...
function newCenter(){
var newc = map.getCenter();
geocoder.geocode({'latLng': newc}, function(results, status){
if (status == google.maps.GeocoderStatus.OK) {
  var newzip = results[0].address_components['postal_code'];
  }
});
};

Of course, this code doesn't actually work. So I was wondering how I would need to change this in order to extract the postal code from the results array. Thanks

Crary answered 17/3, 2011 at 15:12 Comment(3)
EDIT: It looks like I have no choice but to iterate through the address components and search for one with types[0] == 'postal_code' ? Is there a better way to do that?Crary
@RomainM yes i would assume unless u want to manually parse it from the resultNever
Yes, you do have to go through the array and look for the element that has 'postal_code' in its types array, which may be last or first or anywhere in between. Besides, which element? You may want to take the postal code from results[0].address_components or from results itself: try with both and see what works best in the area you care about. In general, I'd recommend results[0].address_components if you care about places with a full address, and results if you case about strict containment of your latlng in the postal code you get.Studied
C
12

Alright, so I got it. The solution is a little uglier than I'd like, and I probably don't need the last for loop, but here's the code for anyone else who needs to extract crap from address_components[]. This is inside the geocoder callback function

// make sure to initialize i
for(i=0; i < results.length; i++){
            for(var j=0;j < results[i].address_components.length; j++){
                for(var k=0; k < results[i].address_components[j].types.length; k++){
                    if(results[i].address_components[j].types[k] == "postal_code"){
                        zipcode = results[i].address_components[j].short_name;
                    }
                }
            }
    }
Crary answered 17/3, 2011 at 15:44 Comment(4)
this doesn't work for me, I am checking the postal code for Iowa City Iowa and it comes up undefined.Plaintive
This should be the approved answer. This works for addresses that do not have the zip code as the last component.Fortunetelling
hey @SamCromer i tested the above code and the answer also came undefined. maybe you also forgot to put var i= 0 before the for loop. i added and it worked great!Gyration
this works beautifully, just as long as you change 'for(i; i < results.length; i++){' to 'for(i=0; i < results.length; i++){'. many thanks for this solution.Context
A
23

What I've realized so far is that in most cases the ZIPCODE is always the last value inside each returned address, so, if you want to retrieve the very first zipcode (this is my case), you can use the following approach:

var address = results[0].address_components;
var zipcode = address[address.length - 1].long_name;
Antilogism answered 18/3, 2011 at 12:25 Comment(9)
ah, there we go. That's a hell of a lot cleaner. ThanksCrary
I had to use address.length - 2 Not sure why yours is different?Cortes
There's a long time since I published this answer, but I remember that in another project I discovered that the index would vary depending on the result. In other words, the zipcode can sometimes not be the last item.Antilogism
@Tuco, the index does change. Sometimes it is the last element, others, it is the second to last. Not sure the reason for this though.Fortunetelling
Indeed @jmiraglia. Long after I published this response, I discovered that for some reason sometimes it's not the last element. Maybe you can validate the value against a Regex, something like /\d{5}-\d{3}/ could to the trick.Antilogism
Yes, you do have to go through the array and look for the element that has 'postal_code' in its types array, which may be last or first or anywhere in between.Studied
For those who are wondering why zip code comes at the second last position sometimes, it's because in some cases the last item is the postal_code_suffix keyCursorial
it can also miss if you do not provide enough information, and can lead to errorHypermetropia
I was testing out and for few cases address[address.length - 1] returns the desired zip code while in few cases `address[address.length - 2]. So here is a ternary statement var zipcode = isNaN(address[address.length - 1].long_name) ? address[address.length - 2].long_name : address[address.length - 1].long_name;Uncaredfor
C
14

You can do this pretty easily using the underscore.js libraray: http://documentcloud.github.com/underscore/#find

_.find(results[0].address_components, function (ac) { return ac.types[0] == 'postal_code' }).short_name
Coben answered 6/4, 2012 at 17:43 Comment(3)
thanks buddy, pretty nice one-liner using underscore.js' find()Ophthalmitis
The underscore hack is very good. i'm not using underscore in my current project and i don't feel like adding another lib just for it, but i'm bookmarking this answer :DGyration
See this answer https://mcmap.net/q/554515/-retrieving-postal-code-with-google-maps-javascript-api-v3-reverse-geocode with native .find methodHeda
C
12

Alright, so I got it. The solution is a little uglier than I'd like, and I probably don't need the last for loop, but here's the code for anyone else who needs to extract crap from address_components[]. This is inside the geocoder callback function

// make sure to initialize i
for(i=0; i < results.length; i++){
            for(var j=0;j < results[i].address_components.length; j++){
                for(var k=0; k < results[i].address_components[j].types.length; k++){
                    if(results[i].address_components[j].types[k] == "postal_code"){
                        zipcode = results[i].address_components[j].short_name;
                    }
                }
            }
    }
Crary answered 17/3, 2011 at 15:44 Comment(4)
this doesn't work for me, I am checking the postal code for Iowa City Iowa and it comes up undefined.Plaintive
This should be the approved answer. This works for addresses that do not have the zip code as the last component.Fortunetelling
hey @SamCromer i tested the above code and the answer also came undefined. maybe you also forgot to put var i= 0 before the for loop. i added and it worked great!Gyration
this works beautifully, just as long as you change 'for(i; i < results.length; i++){' to 'for(i=0; i < results.length; i++){'. many thanks for this solution.Context
L
12

Using JQuery?

var searchAddressComponents = results[0].address_components,
    searchPostalCode="";

$.each(searchAddressComponents, function(){
    if(this.types[0]=="postal_code"){
        searchPostalCode=this.short_name;
    }
});

short_name or long_name will work above
the "searchPostalCode" var will contain the postal (zip?) code IF and only IF you get one from the Google Maps API.

Sometimes you DO NOT get a "postal_code" in return for your query.

Landlordism answered 9/11, 2011 at 1:42 Comment(0)
R
4
$.each(results[0].address_components,function(index,value){
    if(value.types[0] === "postal_code"){
        $('#postal_code').val(value.long_name);
    }
});
Rigger answered 14/12, 2018 at 16:51 Comment(0)
H
4

You can also use JavaScript .find method which is similar to underscore _.find method but it is native and require no extra dependency.

const zip_code = results[0].address_components.find(addr => addr.types[0] === "postal_code").short_name;
Heda answered 17/7, 2020 at 0:58 Comment(1)
You need a Polyfill for this, cause there is no IE support [caniuse.com/array-find]Firsthand
N
2

This takes only two for loops. The "results" array gets updated once we found the first "type" to be "postal_code".

It then updates the original array with the newly found array set and loops again.

            var i, j,
            result, types;

            // Loop through the Geocoder result set. Note that the results
            // array will change as this loop can self iterate.
            for (i = 0; i < results.length; i++) {

                result = results[i];

                types = result.types;

                for (j = 0; j < types.length; j++) {

                    if (types[j] === 'postal_code') {

                        // If we haven't found the "long_name" property,
                        // then we need to take this object and iterate through
                        // it again by setting it to our master loops array and 
                        // setting the index to -1
                        if (result.long_name === undefined) {
                            results = result.address_components;
                            i = -1;
                        }
                        // We've found it!
                        else {
                            postcode = result.long_name;
                        }

                        break;

                    }

                }

            }
Naominaor answered 22/6, 2011 at 20:50 Comment(0)
L
2

You can also use this code, this function will help to get zip on button click or onblur or keyup or keydown.

Just pass the address to this function.

use google api with valid key and sensor option removed as it doesn't required now.

function callZipAPI(addSearchZip)
{    
    var geocoder = new google.maps.Geocoder();
    var zipCode = null;

    geocoder.geocode({ 'address': addSearchZip }, function (results, status) {
        if (status == google.maps.GeocoderStatus.OK) {

            //var latitude = results[0].geometry.location.lat();
            //var longitude = results[0].geometry.location.lng();

            var addressComponent = results[0].address_components;            
            for (var x = 0 ; x < addressComponent.length; x++) {
                var chk = addressComponent[x];
                if (chk.types[0] == 'postal_code') {
                    zipCode = chk.long_name;
                }
            }
            if (zipCode) {
                alert(zipCode);
            }
            else {
                alert('No result found!!');
            }
        } else {            
            alert('Enter proper address!!');
        }
    });
}
Louella answered 5/9, 2016 at 12:15 Comment(1)
If you want latitude and longitude, just remove the comment part from the two lines mentioned.Louella
N
2

I use this code to get "Postal code" and "locality", but you can use it to get any other field just changing the value of type:

JAVASCRIPT

var address = results[0].address_components;
var zipcode = '';
var locality = '';

for (var i = 0; i < address.length; i++) {
     if (address[i].types.includes("postal_code")){ zipcode = address[i].short_name; }    
     if (address[i].types.includes("locality")){ locality = address[i].short_name; }
}
Neman answered 26/10, 2017 at 14:45 Comment(0)
U
2

I think rather than depending on the index it better checks address type key inside the component. I solved this issue by using a switch case.

      var address = '';
      var pin = '';
      var country = '';
      var state = '';
      var city = '';
      var streetNumber = '';
      var route ='';
      var place = autocomplete.getPlace(); 
      for (var i = 0; i < place.address_components.length; i++) {
        var component = place.address_components[i];
        var addressType = component.types[0];

        switch (addressType) {
            case 'street_number':
                streetNumber = component.long_name;
                break;
            case 'route':
                route = component.short_name;
                break;
            case 'locality':
                city = component.long_name;
                break;
            case 'administrative_area_level_1':
                state = component.long_name;
                break;
            case 'postal_code':
                pin = component.long_name;
                break;
            case 'country':
                country = component.long_name;
                break;
        }
       }
Uphill answered 3/4, 2019 at 14:45 Comment(0)
K
1
places.getDetails( request_details, function(results_details, status){

                // Check if the Service is OK
                if (status == google.maps.places.PlacesServiceStatus.OK) {                  

                    places_postal           = results_details.address_components
                    places_phone            = results_details.formatted_phone_number
                    places_phone_int        = results_details.international_phone_number
                    places_format_address   = results_details.formatted_address
                    places_google_url       = results_details.url
                    places_website          = results_details.website
                    places_rating           = results_details.rating

                    for (var i = 0; i < places_postal.length; i++ ) {
                        if (places_postal[i].types == "postal_code"){
                            console.log(places_postal[i].long_name)
                        }
                    }

                }
            });

This seems to work very well for me, this is with the new Google Maps API V3. If this helps anyone, write a comment, i'm writing my script as we speak... so it might change.

Koodoo answered 27/12, 2011 at 1:22 Comment(0)
H
1

Using JSONPath, it's easily done with one line of code:

var zip = $.results[0].address_components[?(@.types=="postal_code")].long_name;
Heteronomous answered 30/7, 2016 at 21:34 Comment(0)
B
1

In PHP I use this code. Almost in every conditions it works.

$zip = $data["results"][3]["address_components"];
$zip = $index[0]["short_name"];
Bucher answered 3/8, 2017 at 13:53 Comment(0)
P
1

Romaine M. — thanks! If you just need to find the postal code in the first returned result from Google, you can do just 2 loops:

for(var j=0;j < results[0].address_components.length; j++){
    for(var k=0; k < results[0].address_components[j].types.length; k++){
        if(results[0].address_components[j].types[k] == "postal_code"){
            zipcode = results[0].address_components[j].long_name;
        }
    }
}
Peaked answered 29/9, 2017 at 20:31 Comment(0)
E
0

In a word, that's a lot of effort. At least with the v2 API, I could retrieve those details thusly:

var place = response.Placemark[0];
var point = new GLatLng(place.Point.coordinates[1], place.Point.coordinates[0]);

myAddress = place.AddressDetails.Country.AdministrativeArea.SubAdministrativeArea.Locality.Thoroughfare.ThoroughfareName

myCity = place.AddressDetails.Country.AdministrativeArea.SubAdministrativeArea.Locality.LocalityName

myState = place.AddressDetails.Country.AdministrativeArea.AdministrativeAreaName

myZipCode = place.AddressDetails.Country.AdministrativeArea.SubAdministrativeArea.Locality.PostalCode.PostalCodeNumber

There has got to be a more elegant way to retrieve individual address_components without going through the looping jujitsu you just went through.

Eighteen answered 17/3, 2011 at 19:44 Comment(1)
I hope you're right, maybe I just don't get how you're supposed to interact with the object. If you look at the tutorial thing, it's clear that address_components is an array, and since Javascript doesn't have associative arrays, the only way that I can think to do this is with loops code.google.com/apis/maps/documentation/javascript/…Crary
H
0

This simple code works for me

for (var i = 0; i < address.length; i++) {
        alert(address[i].types);
        if (address[i].types == "postal_code")
            $('#postalCode').val(address[i].long_name);
        if (address[i].types == "")
            $('#country').val(address[i].short_name);
    }
Harold answered 19/2, 2015 at 12:49 Comment(0)
V
0

Using Jquery

  • You cant be sure in which location in the address_components array the postal code is stored. Sometimes in address_components.length - 1 > pincode may not be there. This is true in "Address to latlng" geocoding.
  • You can be sure that Postal code will contain a "postal_code" string. So best way is to check for that.
   var postalObject = $.grep(results[0].address_components, function(n, i) {
                                    if (n.types[0] == "postal_code") {
                                        return n;
                                    } else {
                                        return null;
                                    }
                                });

                                $scope.query.Pincode = postalObject[0].long_name;
Vintner answered 11/2, 2016 at 4:52 Comment(0)
C
0
 return $http.get('//maps.googleapis.com/maps/api/geocode/json', {
            params: {
                address: val,
                sensor: false
            }
        }).then(function (response) {
           var model= response.data.results.map(function (item) {
               // return item.address_components[0].short_name;
               var short_name;
             var st=  $.each(item.address_components, function (value, key) {
                    if (key.types[0] == "postal_code") {
                        short_name= key.short_name;
                    }
                });
             return short_name;

            });
                return model;
        });
Cochlea answered 2/3, 2016 at 20:39 Comment(0)
L
0
//autocomplete is the text box where u will get the suggestions for an address.

autocomplete.addListener('place_changed', function () {
//Place will get the selected place geocode and returns with the address              
//and marker information.
        var place = autocomplete.getPlace();
//To select just the zip code of complete address from marker, below loop //will help to find. Instead of y.long_name you can also use y.short_name. 
        var zipCode = null;
        for (var x = 0 ; x < place.address_components.length; x++) {
            var y = place.address_components[x];
            if (y.types[0] == 'postal_code') {
                zipCode = y.long_name;
            }
        }
    });
Louella answered 2/9, 2016 at 17:54 Comment(2)
With auto complete text box you can get the required Postal address,Louella
Please add a bit of explanation with your answer. It might help OP to understand what you are posting here.Festal
P
0

It seems that nowadays it's better to get it from the restful API, simply try:

https://maps.googleapis.com/maps/api/geocode/json?latlng=40.714224,-73.961452&key=YOUR_KEY_HERE

Using an AJAX GET call works perfect!

Something like:

var your_api_key = "***";
var f_center_lat = 40.714224;
var f_center_lon = -73.961452;

$.ajax({ url: "https://maps.googleapis.com/maps/api/geocode/json?latlng="+f_center_lat+","+f_center_lon+"&key="+your_api_key,
            method: "GET"
        })
        .done(function( res ) { if (debug) console.log("Ajax result:"); console.log(res);
            var zipCode = null;
            var addressComponent = res.results[0].address_components;
            for (var x = 0 ; x < addressComponent.length; x++) {
                var chk = addressComponent[x];
                if (chk.types[0] == 'postal_code') {
                    zipCode = chk.long_name;
                }
            }
            if (zipCode) {
                //alert(zipCode);
                $(current_map_form + " #postalcode").val(zipCode);
            }
            else {
                //alert('No result found!!');
                if (debug) console.log("Zip/postal code not found for this map location.")
            }
        })
        .fail(function( jqXHR, textStatus ) {
            console.log( "Request failed (get postal code via geocoder rest api). Msg: " + textStatus );
        });
Paleface answered 26/9, 2017 at 21:18 Comment(0)
A
0

As I got it zip is the last or the one that before last. That why this is my solution

const getZip = function (arr) {
  return (arr[arr.length - 1].types[0] === 'postal_code') ? arr[arr.length - 1].long_name : arr[arr.length - 2].long_name;
};
const zip = getZip(place.address_components);
Aprilette answered 4/3, 2020 at 23:54 Comment(0)
S
0

i think this is the most accurate solution:

zipCode: result.address_components.find(item => item.types[0] === 'postal_code').long_name;
Sternson answered 18/10, 2021 at 8:7 Comment(0)
T
0

Just search for postal_code in all types, and return when found.

const address_components = [{"long_name": "2b","short_name": "2b","types": ["street_number"]}, { "long_name": "Louis Schuermanstraat","short_name": "Louis Schuermanstraat", "types": ["route"]},{"long_name": "Gent","short_name": "Gent","types": ["locality","political" ]},{"long_name": "Oost-Vlaanderen","short_name": "OV","types": ["administrative_area_level_2","political"]},{"long_name": "Vlaanderen","short_name": "Vlaanderen","types": ["administrative_area_level_1","political"]},{"long_name": "België","short_name": "BE","types": ["country","political"]},{"long_name": "9040","short_name": "9040","types": ["postal_code"]}];
    
// address_components = results[0]address_components

console.log({
  'object': getByGeoType(address_components),
  'short_name': getByGeoType(address_components).short_name,
  'long_name': getByGeoType(address_components).long_name,
  'route': getByGeoType(address_components, ['route']).long_name,
  'place': getByGeoType(address_components, ['locality', 'political']).long_name
});


function getByGeoType(components, type = ['postal_code']) {
  let result = null;
  $.each(components,
    function() {
      if (this.types.some(r => type.indexOf(r) >= 0)) {
        result = this;
        return false;
      }
    });
  return result;
}
<script src="https://cdnjs.cloudflare.com/ajax/libs/jquery/3.3.1/jquery.min.js"></script>
Thearchy answered 26/10, 2021 at 14:18 Comment(0)

© 2022 - 2024 — McMap. All rights reserved.