Michael Scott
Michael Scott

Reputation: 45

Keep getting TypeError: Cannot read property 'formatted_address' of undefined

I've created a page where I can paste in addresses in bulk and get them geocoded, done via the Google Geocoding API, and axios. The majority of the addresses get converted into the corresponding latitude and longitude, however some addresses, when I check in the developer console, I get 'TypeError: Cannot read property 'formatted_address' of undefined'. 'formatted_address' is the full address, from the JSON response.

<html lang="en">
<head>
  <meta charset="UTF-8">
  <meta name="viewport" content="width=device-width, initial-scale=1.0">
  <meta http-equiv="X-UA-Compatible" content="ie=edge">
  <script src="https://unpkg.com/axios/dist/axios.min.js"></script>
  <link rel="stylesheet" href="https://maxcdn.bootstrapcdn.com/bootstrap/4.0.0/css/bootstrap.min.css" integrity="sha384-Gn5384xqQ1aoWXA+058RXPxPg6fy4IWvTNh0E263XmFcJlSAwiGgFAW/dAiS6JXm" crossorigin="anonymous">
  <title>Geocoder</title>
</head>

<body>
<div class = "container">

  <!--User input stuff -->
  <br>
  <h3 id = "text-center"> <font color="black"> enter locations: </font></h3>
  <br>
  <form id = "location-form">
    <textarea id = "location-input" rows= 20 class="form-control form-control-lg"> </textarea>
    <br>
    <button type="submit" class="btn btn-primary btn-block"> Submit </button>
  </form>

  <!-- divs for the formatted address & lat and long -->
  <div class="card-block" id="formatted-address"> </div>
  <div class="card-block" id="geometry"> </div>
  <table class="table" id="output-table">
    <thead>
    <tr>
      <th scope="col"> Address </th>
      <th scope="col"> Latitude </th>
      <th scope="col"> Longitude </th>
    </tr>
  </thead>
</table>

<!-- <h7 id = "row-count">Row count</h7> -->

<center> <button type="button btn-primary" class="btn btn-primary" onclick="exportTableToExcel('output-table', 'Geocode-Output')">Export Table Data To Excel File</button> </center>


</div>

  <script>
    alert("Enter the addresses, one address per line, seperated by a comma.")
    //Get the data from the user's input.
    var locationForm = document.getElementById('location-form');
    //Add an event listener which checks if submit is pressed. Once it is, run geocode function
    locationForm.addEventListener('submit', geocode);


    /*Handles the sending of requests to the Google Geocode API, and provides functionality for
    * responding to the API requests.
    */
    function geocode(e) {
      e.preventDefault();
      var location = document.getElementById('location-input').value; //raw data
      //Split the user input into a large array
      var locationArray = location.split(',');
      console.log("There are " + locationArray.length + "  elements in the locationArray");

    for (var i = 0; i < locationArray.length; i++) {
      axios.get('https://maps.googleapis.com/maps/api/geocode/json', {
        params:{
          address:locationArray[i],
          key:'Censored'
        }
      })

      .then(function(response){
        var address = response.data.results[0].formatted_address;
        var lat = response.data.results[0].geometry.location.lat;
        var lng = response.data.results[0].geometry.location.lng;

        var outputTable = document.getElementById('output-table');
        var newRow = outputTable.insertRow(outputTable.rows.length);

        newRow.innerHTML = '<tr><td>' + address + '<tr><td>' + lat + '<tr><td>' + lng;

        console.log(lat);
        console.log(lng);
      })

      //Handle errors
      .catch(function(error){
        console.log(error);
      });
    }
  }

  function exportTableToExcel(tableID, filename) {
    var downloadLink;
    var dataType= 'application/vnd.ms-excel';
    var tableSelect = document.getElementById(tableID);
    var tableHTML = tableSelect.outerHTML.replace(/ /g, '%20');

    //Specify the filename
    filename = filename?filename+'.xls':'excel_data.xls';

    //create download link element
    downloadLink = document.createElement("a");

    document.body.appendChild(downloadLink);

    if(navigator.msSaveOrOpenBlob){
      var blob = new Blob(['\ufeff', tableHTML], {
        type: dataType
      });
    navigator.msSaveOrOpenBlob( blob, filename);
      } else {
    // Create a link to the file
    downloadLink.href = 'data:' + dataType + ', ' + tableHTML;
    //Setting the file filename
    downloadLink.download = filename;
    //triggering the function
    downloadLink.click();
    }
  }
  </script>

</body>
</html>

The error occurs at 'var address = response.data.results[0].formatted_address;'

Upvotes: 1

Views: 2336

Answers (1)

xomena
xomena

Reputation: 32158

You should be aware that Geocoding API web service can return different statuses in response. If everything works as expected you will get "OK" status and in this case the response.data.results[0] won't be undefined, for other statuses the results array is empty, so you don't have element with index 0.

Have a look at the complete list of possible statuses in the documentation:

https://developers.google.com/maps/documentation/geocoding/requests-geocoding#StatusCodes

Referring to your code you should check and handle status field of response.

axios.get('https://maps.googleapis.com/maps/api/geocode/json', {
    params:{
        address:locationArray[i],
        key:'Censored'
    }
}).then(function(response) {
    //First check status
    const status = response.data.status;
    if (status==="OK") { 
        var address = response.data.results[0].formatted_address;
        var lat = response.data.results[0].geometry.location.lat;
        var lng = response.data.results[0].geometry.location.lng;

        var outputTable = document.getElementById('output-table');
        var newRow = outputTable.insertRow(outputTable.rows.length);

        newRow.innerHTML = '<tr><td>' + address + '<tr><td>' + lat + '<tr><td>' + lng;

        console.log(lat);
        console.log(lng);
    } else if (status==="ZERO_RESULTS") {
        //Handle zero results here
    } else if (status==="OVER_QUERY_LIMIT") {
        //Handle over query per second limit using exponential back off here 
    } else if (status==="REQUEST_DENIED") {
        //Handle request denied here
    } else if (status==="INVALID_REQUEST") {
        //Handle invalid request here
    } else if (status==="UNKNOWN_ERROR") {
        //Handle server error here
    }
})
//Handle errors
.catch(function(error){
    console.log(error);
});

I hope this helps!

Upvotes: 1

Related Questions