0

I want to display the results of an ajax post mysql query, and further refine by the result to getDistanceMatrix, which is an asynchronous function that returns a distance value as part of a callback.

I've read several posts about asycnhronous functions (eg How do I return the response from an asynchronous call? and others) and opted to use a callback as the simplest to understand method, but can't get it to work and have hit a brick wall.

I'm using javascript and some php and got it working to display the result if I don't run getDistanceMatrix, but can't work out how to get the kms value out of the function to be available for the if statement, to further refine the results to be displayed. I have also tried including the if statement (and table html) in the callback function Callback_calcDistance(kms) but then nothing gets displayed. I think the problem is that code is finishing before the getDistanceMatrix has finished, but don't know how to get the result out of this function in time for running the table html. I've included the javascript part below.

` $(document).ready(function(){

$("#findride").submit(function(){
//js variables from form
  $.ajax({
    url: 'includes/findride.inc.php',
    type: 'POST',
    dataType:"json",
    data: { rdate:rdate, rtime:rtime, },
    success: function(data) {
    //isEmpty function
      if(isEmpty(data)) {
          $("#result").html("<p class='loginError' >No Rides match your Search</p>");
      }
      else
      {
        var output =
          "<table><thead><tr><th class='tablehdr-15'>Ride ID</th><th class='tablehdr-60'>Destination</th><th class='tablehdr-25'>Arrival Time</th></thead><tbody>";

        for (var i in data) {

          var driver_lng = data[i].user_lng;
          // other variables from mysql

          var origin = new google.maps.LatLng(-36.78961120, 174.75189440);
          var destination = new google.maps.LatLng(-36.80272570, 174.74423420);
          var distanceResult1;

          function calcDistance (fromLat, fromLng, toLat, toLng) {
            return  google.maps.geometry.spherical.computeDistanceBetween(
              new google.maps.LatLng(fromLat, fromLng), new google.maps.LatLng(toLat, toLng));
          }

          var calcD = calcDistance(latdb, lngdb, lats, lngs);

          calculateDistanceDriver(origin, destination, Callback_calcDistance);

          function calculateDistanceDriver(origin, destination, ref_Callback_calcDistance) {
            var service = new google.maps.DistanceMatrixService();
            var kms;

            service.getDistanceMatrix(
            {
              origins: [origin],
              destinations: [destination],
              travelMode: google.maps.TravelMode.DRIVING,
              unitSystem: google.maps.UnitSystem.METRIC
            }, function (response, status) {
              if (status != google.maps.DistanceMatrixStatus.OK) {
                $('#result1').html(err);
              }
              else
              {
                var origin = response.originAddresses[0];
                var destination = response.destinationAddresses[0];
                if (response.rows[0].elements[0].status === "ZERO_RESULTS") {
                  $('#result1').html("No result for this search");
                }
                else
                {
                  var distance = response.rows[0].elements[0].distance;
                  var distance_value = distance.value;
                  var distance_text = distance.text;
                  var kms = distance_text.substring(0, distance_text.length - 3);

                  //How can I make kms available for the if ((calcD < 2000) .. statement below?

                  $('#result1').html("Result = " + kms);
                  console.log("distance result a " + kms);
                  if(typeof ref_Callback_calcDistance === 'function'){

                      ref_Callback_calcDistance(kms)
                  }
                }
              }
            });
          }
          function Callback_calcDistance(kms) {
              console.log("distanceResult " + kms);
              distanceResult1 = kms;
          }
          console.log("distanceResult1 " + distanceResult1);



          //I want to use kms here for following if statement

          // if ((calcD < 2000) && (seatsreq <= freeseats) && (distanceResult1 <= extra_dist)) {
          if ((calcD < 2000) && (seatsreq <= freeseats)) {
            output +=
              "<tr><td class='tablehdr-15'>" +
              data[i].ride_id +
              "</td><td class='tablehdr-60'><a href='includes/ridedetails.inc.php?rideid=" + data[i].ride_id + "' target='_blank'>" +
              data[i].dest_address +
              "</a></td><td class='tablehdr-25'>" +
              data[i].ride_time +
              "</td></tr>";
          }
        }
        output += "</tbody></table>";
        $("#result").html(output);
        $("table").addClass("table-300");
      }
    },
    error: function(e) {
    console.log(e.message);
    }
  });
  event.preventDefault();
});

}); `

I expect to be able to further refine the results from the ajax post, using the result from the getDistanceMatrix call.

  • asynchronous callbacks in a for statement = recursion –  Apr 05 '19 at 05:39
  • try `for (let i in data)` instead – Jaromanda X Apr 05 '19 at 05:39
  • @RemisaYousefvand no, recursion is nothing to do with asynchrony, callbacks nor for loops – Jaromanda X Apr 05 '19 at 05:40
  • how do you approach it to prevent recursion? – feaseyweiss Apr 05 '19 at 05:41
  • @feaseyweiss there's no recursion, so nothing to prevent ... try the simplest solution `for (let` instead of `for (var` ... the issue you are having is that `i` won't be what you expect it to be after asynchronous code calls the callback - however, using `let`, it will be exactly what you expect because of the `block scope` of `let` – Jaromanda X Apr 05 '19 at 05:42
  • @Jaromanda I tried let and still get distanceResult1 undefined – feaseyweiss Apr 05 '19 at 05:44
  • use `let` instead of `var` at the top of the for loop as well, for the same reason, for `driver_lng`, `origin`, etc etc ... there's virtually no reason to use `var` :p – Jaromanda X Apr 05 '19 at 05:44
  • that is, i ran console.log on distanceResult1 just before the if statement and outside of teh callback – feaseyweiss Apr 05 '19 at 05:47

2 Answers2

1

Here is the solution. I moved the if statement inside the callback and created a second output variable as a new table.

<main>
          <script src="https://ajax.googleapis.com/ajax/libs/jqueryui/1.8/jquery-ui.min.js"></script>
            <script src="https://maps.googleapis.com/maps/api/js?key=API_KEY&libraries=places,geometry&callback=initAutocomplete"
            async defer></script>

            <script>
                $(document).ready(function(){

                    $("#findride").submit(function(){

                        var rdate = $("#rdate").val();
                        var rtime = $("#rtime").val();
                        console.log(rtime);
                        console.log(rdate);
                        var lats = $("#lat").val();
                        var lngs = $("#lng").val();
                        var seatsreq = $("#seatsreq").val();
                        var kms;

                        $.ajax({
                          url: 'includes/findride1.inc.php',
                          type: 'POST',
                            dataType:"json",
                          data: {   rdate:rdate, rtime:rtime, seatsreq:seatsreq },
                          success: function(data) {
                                console.log(data);

                                function isEmpty(obj) {
                                        for(var key in obj) {
                                                if(obj.hasOwnProperty(key))
                                                        return false;
                                        }
                                        return true;
                                }

                                if(isEmpty(data)) {
                                        $("#result").html("<p class='loginError' >No Rides match your Search</p>");
                                }
                                else
                                {
                                    var output =
                                        "<table><thead><tr><th class='tablehdr-15'>Ride ID</th><th class='tablehdr-60'>Destination</th><th class='tablehdr-25'>Arrival Time</th></thead><tbody></tbody></table>";

                                        $("#result").html(output);
                                        $("table").addClass("table-300");
                                        //$("#result").hide();
                                    var output1 = "<table><tbody>";

                                    for (let i in data) {
                                        var latdb = data[i].lat;
                                        var lngdb = data[i].lng;

                                        var extra_dist = data[i].extra_dist;
                                        var freeseats = data[i].free_seats;
                                        var driver_lat = data[i].user_lat;
                                        var driver_lng = data[i].user_lng;
                                        var driver_dist = data[i].driver_dist;

                                        var origin = new google.maps.LatLng(-36.78961120, 174.75189440);
                                        var destination = new google.maps.LatLng(-36.80272570, 174.74423420);

                                        var origin1 = "-36.78961120, 174.75189440";
                                        var destination1 = "-36.80272570, 174.74423420";

                                        var distanceResult1;
                                        var directionsService = new google.maps.DirectionsService();
                                        var service = new google.maps.DistanceMatrixService();

                                        var calcD = calcDistance(latdb, lngdb, lats, lngs);

                                        function calcDistance (fromLat, fromLng, toLat, toLng) {
                                      return  google.maps.geometry.spherical.computeDistanceBetween(
                                        new google.maps.LatLng(fromLat, fromLng), new google.maps.LatLng(toLat, toLng));
                                    }

                                        calcRoute();

                                        function calcRoute() {
                                          var waypts = [
                                                {
                                                    location: "-36.7612802,174.7516339",
                                                    stopover: true
                                                }
                                            ];

                                          var request = {
                                            origin: origin1,
                                            destination: destination1,
                                            waypoints: waypts,
                                            optimizeWaypoints: false,
                                            travelMode: google.maps.TravelMode.DRIVING,
                                                unitSystem: google.maps.UnitSystem.METRIC
                                          };

                                          directionsService.route(request, function(response, status) {
                                            if (status == google.maps.DirectionsStatus.OK) {

                                              var total_distance = 0.0;
                                              for (var i=0; i<response.routes[0].legs.length; i++) {
                                                total_distance += response.routes[0].legs[i].distance.value;
                                                }
                                              console.log("distance value " + total_distance);
                                            }
                                          });
                                        }

                                        calculateDistanceDriver(origin, destination, Callback_calcDistance);

                                        function calculateDistanceDriver(origin, destination, ref_Callback_calcDistance) {

                                            service.getDistanceMatrix(
                                            {
                                                origins: [origin],
                                                destinations: [destination],
                                                travelMode: google.maps.TravelMode.DRIVING,
                                                unitSystem: google.maps.UnitSystem.METRIC,
                                                avoidHighways: false,
                                                avoidTolls: false
                                            }, function (response, status) {
                                                if (status != google.maps.DistanceMatrixStatus.OK) {
                                                    $('#result1').html(err);
                                                }
                                                else
                                                {
                                                    var origin = response.originAddresses[0];
                                                    var destination = response.destinationAddresses[0];
                                                    if (response.rows[0].elements[0].status === "ZERO_RESULTS") {
                                                        $('#result1').html("No result for this search");
                                                    }
                                                    else
                                                    {
                                                        var distance = response.rows[0].elements[0].distance;
                                                        var distance_value = distance.value;
                                                        var distance_text = distance.text;
                                                        var kms = distance_text.substring(0, distance_text.length - 3);

                                                        //$('#result1').html("Result = " + kms);
                                                        // console.log("distance result a " + kms);
                                    if(typeof ref_Callback_calcDistance === 'function'){

                                        ref_Callback_calcDistance(kms)
                                    }
                                                    }
                                                }
                                            });
                                        }
                                        function Callback_calcDistance(kms) {

                                            distanceResult1 = kms;

                                            if ((calcD < 2000) && (distanceResult1 <= extra_dist)) {
                                                console.log("distanceResult1 <= extra_dist & calD" + data[i].ride_id);
                                                output1 +=
                                                    "<tr><td class='tablehdr-15'>" +
                                                    data[i].ride_id +
                                                    "</td><td class='tablehdr-60'><a href='includes/ridedetails.inc.php?rideid=" + data[i].ride_id + "' target='_blank'>" +
                                                    data[i].dest_address +
                                                    "</a></td><td class='tablehdr-25'>" +
                                                    data[i].ride_time +
                                                    "</td></tr>";
                                                    $("#result1").html(output1);
                                                $("#infotext").html("The following rides meet your search criteria. Click on the ride to get more information");

                                            } else {
                                                //$("#result").html("<p class='loginError' >No Rides match your Search</p>");
                                            }
                                        }
                                    }
                                    var output2 = "</tbody></table>";
                                    $("#result2").html(output2);

                                    //$("table").addClass("table-300");
                                }
                          },
                          error: function(e) {
                            console.log(e.message);
                          }
                        });
                        event.preventDefault();
                    });
                });
            </script>
            <div class="main-wrapper">
                <h3 class="h3-heading">Find Ride</h3>

                <form class="form-wrapper" id="findride" action="includes/findride.inc.php" method="post">

                    <p class="pTextsm">Date of Travel</p>
              <input class="def-form" type="date" id="rdate" name="rdate"><br>
                    <p class="pTextsm">Arrival Time at Destination</p>
              <input class="def-form" type="time" id="rtime" name="rtime" value="12:00"><br>
                    <p class="pTextsm">Seats required</p>
                    <input class="def-formB" type="text" id="seatsreq" name="seatsreq"><br>
                    <p class="pTextsm">Destination Address (if no result enter surburb and map will display. Then place marker to get address) </p>
                    <input class="def-form" type="text" id="autocomplete" onFocus="geolocate()" name="address"><br>
                    <div id="maprd" style="display: none;"></div>
                    <!-- <p class="pTextsm">Pick up Address</p>
                    <p class="pTextsm" id="addresspickupdef"></p>
                    <p class="pTextsm">(enter only if different from your Account Address)</p>
                    <input class="def-form" type="text" id="autocompletepickup" onFocus="geolocate()" name="pickupaddress"><br> -->
                    <input type="hidden" id="place_id" name="place_id" value="test">
                    <input type="hidden" id="lat" name="lat">
                    <input type="hidden" id="lng" name="lng">
                    <input type="hidden" id="place_idpickup" name="place_idpickup" value="test">
                    <input type="hidden" id="latpickup" name="latpickup">
                    <input type="hidden" id="lngpickup" name="lngpickup">
                    <!-- <input type="hidden" id="seatsreq" name="seatsreq"> -->
                    <input type="hidden" id="latlngnew" type="text" value="40.714224,-73.961452">
                    <button class="def-form-button" type="submit" id="ridesub" name="ridesub">Find Ride</button>
                </form>
                <div id="infotext"></div>
                <div id="result"></div>
                <div id="result1"></div>
                <div id="result2"></div>
                <div id="norides"></div>
                <div id="placeidshow"></div>
                <div id="latsdiv"></div>
                <div id="lngsdiv"></div>
                <div id="latdbdiv"></div>
                <div id="lngdbdiv"></div>
                <div id="calcDdiv"></div>
                <div id="calcseatsavail"></div>
                <div id="seatsreq1"></div>


            </div>
        </main>
        <script>

            var placeSearch, autocomplete, autocompletepickup, placeId, placeIdpickup;

            function initAutocomplete() {

                autocomplete = new google.maps.places.Autocomplete(
                        /** @type {!HTMLInputElement} */(document.getElementById('autocomplete')),
                        {types: ['geocode']});

                autocomplete.setComponentRestrictions(
            {'country': ['nz']});

                autocomplete.addListener('place_changed', fillInAddress);

                autocompletepickup = new google.maps.places.Autocomplete(
                        /** @type {!HTMLInputElement} */(document.getElementById('autocompletepickup')),
                        {types: ['geocode']});

                autocompletepickup.setComponentRestrictions(
            {'country': ['nz']});

                autocompletepickup.addListener('place_changed', fillInAddresspickup);
            }

            function fillInAddress() {

                var place = autocomplete.getPlace();
                var lat = place.geometry.location.lat();
        var lng = place.geometry.location.lng();

                document.getElementById('lat').value = lat;
                document.getElementById('lng').value = lng;

                placeId = place.place_id;
                document.getElementById('place_id').value = placeId;

                $("#maprd").css("display", "block");
                myMap(lat,lng);
                //$('#placeidshow').html(lat);
            }

            function fillInAddresspickup() {

                var place = autocompletepickup.getPlace();
                var lat = place.geometry.location.lat();
        var lng = place.geometry.location.lng();

                document.getElementById('latpickup').value = lat;
                document.getElementById('lngpickup').value = lng;

                placeId = place.place_id;
                document.getElementById('place_idpickup').value = placeId;
                //$('#placeidshow').html(lat);
            }

            function geolocate() {
                if (navigator.geolocation) {
                    navigator.geolocation.getCurrentPosition(function(position) {
                        var geolocation = {
                            lat: position.coords.latitude,
                            lng: position.coords.longitude
                        };
                        var circle = new google.maps.Circle({
                            center: geolocation,
                            radius: position.coords.accuracy
                        });
                        autocomplete.setBounds(circle.getBounds());
                    });
                }
            }
        </script>
        <script>
            var map, marker, newmarker, geocoder, infowindow, newmarkerlat, newmarkerlng;
                function myMap(lat,long) {
                    var myCenter = new google.maps.LatLng(lat,long);
                    var mapCanvas = document.getElementById("maprd");

                    var mapOptions = {
                            center: myCenter,
                            zoom: 18
                            // streetViewControl: false,
                            // mapTypeControl: false
                    };

                    map = new google.maps.Map(mapCanvas, mapOptions);
                    marker = new google.maps.Marker(
                            {
                                    position:myCenter,
                                    draggable: true
                            }
                    );
                    marker.setMap(map);

                    google.maps.event.addListener(marker,'click',function() {
                            //map.setZoom(12);
                            map.setCenter(marker.getPosition());
                    });

                    google.maps.event.addListener(map, 'click', function(event) {
                        newmarkerlat = event.latLng.lat();
                        newmarkerlng = event.latLng.lng();
                        var newmarkerlatlng = "" + newmarkerlat + "," + newmarkerlng;
                        document.getElementById('latlngnew').value = newmarkerlatlng;
                        placeMarker(map, event.latLng);

                        // console.log(document.getElementById('latlngnew').value);
                    });

                }

            function placeMarker(map, location) {
              var marker = new google.maps.Marker({
                position: location,
                map: map
              });

                infowindow = new google.maps.InfoWindow;
                geocoder = new google.maps.Geocoder;
                geocodeLatLng(geocoder, map, infowindow);

            }

            function geocodeLatLng(geocoder, map, infowindow) {
        var input = document.getElementById('latlngnew').value;
        var latlngStr = input.split(',', 2);
        var latlng = {lat: parseFloat(latlngStr[0]), lng: parseFloat(latlngStr[1])};

        geocoder.geocode({'location': latlng}, function(results, status) {
          if (status === 'OK') {
            if (results[0]) {
              //map.setZoom(11);
              var marker = new google.maps.Marker({
                position: latlng,
                map: map
              });
              infowindow.setContent(results[0].formatted_address);
              infowindow.open(map, marker);
                            document.getElementById('autocomplete').value = results[0].formatted_address;

            } else {
              window.alert('No results found');
            }
          } else {
            window.alert('Geocoder failed due to: ' + status);
          }
        });
      }

        </script>


0

Declared var kms in globally then you will get kms value.

Callback_calcDistance() function is not called so check that.

Arun Kumar
  • 121
  • 10
  • I tried that. As getDistanceMatrix runs async, it is not returning the result before the code completes, so kms still appears as undefined – feaseyweiss Apr 05 '19 at 06:47
  • check Callback_calcDistance() function call after assigning kms value. – Arun Kumar Apr 05 '19 at 06:54
  • I can access kms via the callback function Callback_calcDistance(kms) and checked with console.log("distanceResult " + kms); but can't get it out of the call back. – feaseyweiss Apr 05 '19 at 06:58
  • Callback_calcDistance(kms) function called reference parameter function ref_Callback_calcDistance(kms) right – Arun Kumar Apr 05 '19 at 07:02
  • other way around i think?? Callback_calcDistance(kms) is passed via ref_Callback_calcDistance(kms) – feaseyweiss Apr 05 '19 at 07:13
  • Callback_calcDistance(kms) is called as part of getDistanceMatrix, and produces a result through console.log – feaseyweiss Apr 05 '19 at 07:29
  • Here I mentioned the same link check this https://codepen.io/arunram860/pen/axNQvY – Arun Kumar Apr 05 '19 at 08:22
  • Thanks for this Arun, I've got to the same point but can't get the result from function sample(d) into code outside of teh function – feaseyweiss Apr 05 '19 at 08:48
  • console.log("distanceResult1 " + distanceResult1); This distanceResult execute first because it's in outside the function.The function execute when we call the function but other lines don't depend on function.so you can access only within function. – Arun Kumar Apr 05 '19 at 09:07
  • What problem is function process takes more time so console result produce empty.here I mentioned the proof link check it https://codepen.io/arunram860/pen/axNQvY?editors=1010 – Arun Kumar Apr 05 '19 at 09:41
  • Ok, that is what I thought, so if I can't get distanceResult1 from the call back before running the if ((calcD < 2000) && (seatsreq <= freeseats) && (distanceResult1 <= extra_dist)) ... how do i run this piece of code inside the call back function? I tried moving it inside teh function but produces no html – feaseyweiss Apr 05 '19 at 10:55
  • I've played around with moving the html code inside the call back and got it to produce some html. You didn't quite answer my question Arun, but I appreciate your efforts. I'll put up my answer once I have got it working smoothly with css – feaseyweiss Apr 05 '19 at 11:41