-1

I have an issue in my google api code. The problem is I used geocoding in bootstrap modal, on first clik when i filled the inputs I have information in console: Cannot read property of null. Here is sample of my code:

var location1;
var location2;
function licz() {
        var geocoder = new google.maps.Geocoder();

        if (geocoder) {
            geocoder.geocode({ 'address': document.getElementById('txtMiasto1').value }, function (results, status) {
                if (status == google.maps.GeocoderStatus.OK) {
                    location1 = results[0].geometry.location;
                    console.log(location1);

                } else {
                    alert("Geocode was not successful for the following reason: " + status);
                }
            });
            geocoder.geocode({ 'address': document.getElementById('txtMiasto2').value }, function (results, status) {
                if (status == google.maps.GeocoderStatus.OK) {
                    location2 = results[0].geometry.location;
                    console.log(location2);

                } else {
                    alert("Geocode was not successful for the following reason: " + status);

            latlng = new google.maps.LatLng((location1.lat() + location2.lat()) / 2, (location1.lng() + location2.lng()) / 2);



            var mapOptions = {
                center: latlng,
                zoom: 15,
                mapTypeId: google.maps.MapTypeId.ROADMAP
            }
            map = new google.maps.Map(document.getElementById('map-canvas'), mapOptions);

            directionsService = new google.maps.DirectionsService();
            directionsDisplay = new google.maps.DirectionsRenderer(
            {
                suppressMarkers: true,
                suppressInfoWindows: true
            });
            directionsDisplay.setMap(map);
            var request = {
                origin: location1,
                destination: location2,
                travelMode: google.maps.DirectionsTravelMode.DRIVING
            };
            directionsService.route(request, function (response, status) {
                if (status == google.maps.DirectionsStatus.OK) {
                    directionsDisplay.setDirections(response);
                    distance = response.routes[0].legs[0].distance.text;
                    document.getElementById("txtDistance").value = distance;
                }
            });

            var marker1 = new google.maps.Marker({
                map: map,
                position: location1,
                title: "Start"
            });

            var marker2 = new google.maps.Marker({
                map: map,
                position: location2,
                title: "Koniec"
            });

        }
var geocoder = new google.maps.Geocoder();

        if (geocoder) {
            geocoder.geocode({ 'address': document.getElementById('txtMiasto1').value }, function (results, status) {
                if (status == google.maps.GeocoderStatus.OK) {
                    location1 = results[0].geometry.location;
                    console.log(location1);

                } else {
                    alert("Geocode was not successful for the following reason: " + status);
                }
            });
            geocoder.geocode({ 'address': document.getElementById('txtMiasto2').value }, function (results, status) {
                if (status == google.maps.GeocoderStatus.OK) {
                    location2 = results[0].geometry.location;
                    console.log(location2);

                } else {
                    alert("Geocode was not successful for the following reason: " + status);
                }
            });

        }

The function licz() is handled OnClick in button on modal like this:

<button type="button" runat="server" id="btnLicz" class="btn btn-info" onclick="licz();">Calculate</button>

When i Click again the problem solved.

Could someone of You tell me what I'm doing wrong?

Thanks for help!

n00dl3
  • 21,213
  • 7
  • 66
  • 76
k1dl3r
  • 103
  • 1
  • 2
  • 11
  • 1
    where is this error thrown ? – n00dl3 Nov 17 '16 at 11:02
  • When i first time click the button the error message is "location1 is undefined" or "location1 cannot read property of null" Sorry but im not on my computer right now – k1dl3r Nov 17 '16 at 11:10
  • 1
    It's still unclear as there are many references to location1 in your code. When you go back to your computer, please provide the exact line where the error is thrown in your code. – n00dl3 Nov 17 '16 at 11:24
  • in line ' latlng = new google.maps.LatLng((location1.lat() + location2.lat()) / 2, (location1.lng() + location2.lng()) / 2); ' – k1dl3r Nov 17 '16 at 11:31

1 Answers1

1

geocoder.geocode() calls are asynchronous. It means when you call:

latlng = new google.maps.LatLng((location1.lat() + location2.lat()) / 2, (location1.lng() + location2.lng()) / 2);

location1 is not define yet.

To avoid this, you must build something like this:

geocoder.geocode({ 'address': document.getElementById('txtMiasto1').value }, function (results, status) {
  if (status == google.maps.GeocoderStatus.OK) {
    location1 = results[0].geometry.location;
    geocoder.geocode({ 'address': document.getElementById('txtMiasto2').value }, function (results, status) {
      if (status == google.maps.GeocoderStatus.OK) {
        location2 = results[0].geometry.location;
        latlng = new google.maps.LatLng((location1.lat() + location2.lat()) / 2, (location1.lng() + location2.lng()) / 2);
      } else {
        alert("Geocode was not successful for the following reason: " + status);
      }
    });
  } else {
    alert("Geocode was not successful for the following reason: " + status);
  }
});

However there are more elegant ways to handle this kind of situation, like promises (es6 feature, but libraries exist):

var location1;
var location2;

function geocode(data){
  return new Promise((resolve,reject)=>{
    geocoder.geocode(data, (results, status) => {
      if (status == google.maps.GeocoderStatus.OK) 
        resolve(results[0].geometry.location);
      else
        reject();
    });
  })
}
var asyncs=[
  geocode({ 'address': document.getElementById('txtMiasto1').value }).then(result=>location1=result),
  geocode({ 'address': document.getElementById('txtMiasto2').value }).then(result=>location2=result)
]
Promise.all(asyncs).then(()=>{
  //do stuffs with location1 and location2
}).catch(()=>{
  //handle errors
})

Note that this code will work on modern browser (that support arrow functions and Promises, like Chrome, and Firefox), but you can replace arrow function by plain old function(){} and use a promise library like this one (first google result, never tested)

n00dl3
  • 21,213
  • 7
  • 66
  • 76