1

Based on the user location and a store location I try to figure out what the distance is between the two. This is working, but what I want is an array with all the values and sort on the distance between the two points.

I have my add_stores_to_array function, which adds all stores to the array stores when it is looping through the JSON file.

add_stores_to_array = function(position) {
    var user_latitude = position.coords.latitude;
    var user_longitude = position.coords.longitude;

    $.getJSON('/stores').done(function(data) {

        $.each(data.features, function(i, item) {
            var store_latitude = item.geometry.coordinates[1];
            var store_longitude = item.geometry.coordinates[0];

            var user = new google.maps.LatLng(user_latitude, user_longitude);
            var store = new google.maps.LatLng(store_latitude, store_longitude);
            
            var directionsService = new google.maps.DirectionsService();
            
            var request = {
                origin:user,
                destination:store,
                travelMode: google.maps.DirectionsTravelMode.DRIVING
            };

            directionsService.route(request, function(response, status) {
                if (status == google.maps.DirectionsStatus.OK) {
                    var response = Math.ceil(response.routes[0].legs[0].distance.value / 1000);

                    // add distance and store id to the array stores
                    stores.push({distance: response, id: item.properties.Nid});
                }
            });
        });

        // call the sort function
        sort_stores(stores);

        console.log(stores);

    });
};

After the $.each I call the sort function. But after logging it to the console, it is still not sorted.

My sort_stores function:

sort_stores = function(stores){
    stores.sort(function(a, b){
        return a.distance - b.distance;
    });
};

First I thought it wasn't working because the $.each was still running, but after adding this code, it still doesn't working:

if (i == Object.keys(data.features).pop()) {
    sort_stores(stores);
}   

So, I tried something different. I call the sort_stores(stores) function in the $.each.

directionsService.route(request, function(response, status) {
    if (status == google.maps.DirectionsStatus.OK) {
        var response = Math.ceil(response.routes[0].legs[0].distance.value / 1000);

        stores.push({distance: response, id: item.properties.Nid});
        sort_stores(stores);
    }
});

And it works... the array is sorted based on the value distance in the array. But now he sorts the array after each added store... not really effective.

Is there a proper way to call the sort_stores(stores) function one time, and sort it when all stores are added to the array?

EDIT:

If I place an alert() before the sort_stores(stores) it is working..

                if (status == google.maps.DirectionsStatus.OK) {
                    var response = Math.ceil(response.routes[0].legs[0].distance.value / 1000);

                    stores.push({distance: response, id: item.properties.Nid});
                }
            });
        });
        
        alert('Call the sort_stores(stores) function after the $.each, with an alert.. it is working?');
        sort_stores(stores);
    });
};

Edit 2:

Normally I call the function add_stores_to_array from here?

get_user_location = function(){
    if (navigator.geolocation) {
        navigator.geolocation.getCurrentPosition(add_stores_to_array);
    }
};
8
  • try a.distance > b.distance ? 1 : a.distance < b.distance ? -1 : 0 Commented Nov 11, 2016 at 9:41
  • Hm, it looks like the function stores.sort(function(a, b) is not even running if I place it after the $.each? If I place an alert() inside the stores.sort(function(a, b) nothings happend? Commented Nov 11, 2016 at 9:49
  • did you check the console for errors? edit: nothing's wrong with your sort function. once you get the function working, it will work accordingly. Commented Nov 11, 2016 at 9:52
  • Yes, but there are no erros.. please see my edit in my first post. Commented Nov 11, 2016 at 9:58
  • well it's in the $.getJSON('/stores').done(function(data) { } block and supposed to work after $.each(). there should be an error. check with chrome if you didn't do so. edit: ok, looks like a race condition due to an async call. Commented Nov 11, 2016 at 9:58

1 Answer 1

1

There's nothing wrong with your sort function. The problem is that directionsService.route is asynchronous call and the rest of the code will run even when all the calls are not completed yet.

You can use jQuery.when(). Here is the new add_stores_to_array() function

add_stores_to_array = function(position) {
    var promises = []; //ADDED promise array
    var user_latitude = position.coords.latitude;
    var user_longitude = position.coords.longitude;

    $.getJSON('/stores').done(function(data) {
        $.each(data.features, function(i, item) {
            var store_latitude = item.geometry.coordinates[1];
            var store_longitude = item.geometry.coordinates[0];

            var user = new google.maps.LatLng(user_latitude, user_longitude);
            var store = new google.maps.LatLng(store_latitude, store_longitude);

            var directionsService = new google.maps.DirectionsService();

            var request = {
                origin:user,
                destination:store,
                travelMode: google.maps.DirectionsTravelMode.DRIVING
            };

            var dfd = directionsService.route(request, function(response, status) {
                if (status == google.maps.DirectionsStatus.OK) {
                    var response = Math.ceil(response.routes[0].legs[0].distance.value / 1000);

                    // add distance and store id to the array stores
                    stores.push({distance: response, id: item.properties.Nid});
                }
            });

            promises.push(dfd); //ADDED store each object in array
        });

        //Now you can do the following without having any async issue.
        $.when.apply(null, promises).done(function() { 
           /* sort & do stuff here */ 
           sort_stores(stores);
           console.log(stores);
        });
    });
};

EDIT

Here is another approach. Since you need to wait until all responses are returned, you can customize your sort function to check for the response count. If it's equal to total (which means all calls have finished successfully) then sort the array.

sort_stores = function(stores, responseCount, totalCount ) {
    if (responseCount == totalCount) {
        stores.sort(function(a, b){
            return a.distance - b.distance;
        });
    }
};

Then change the add_stores_to_array function as follows.

add_stores_to_array = function(position) {
    var user_latitude = position.coords.latitude;
    var user_longitude = position.coords.longitude;

    $.getJSON('/stores').done(function(data) {
        var totalCount = data.features.length; //ADDED Get total count
        var responseCount = 0; //ADDED
        $.each(data.features, function(i, item) {
            var store_latitude = item.geometry.coordinates[1];
            var store_longitude = item.geometry.coordinates[0];

            var user = new google.maps.LatLng(user_latitude, user_longitude);
            var store = new google.maps.LatLng(store_latitude, store_longitude);

            var directionsService = new google.maps.DirectionsService();

            var request = {
                origin:user,
                destination:store,
                travelMode: google.maps.DirectionsTravelMode.DRIVING
            };

            directionsService.route(request, function(response, status) {
                if (status == google.maps.DirectionsStatus.OK) {
                    var response = Math.ceil(response.routes[0].legs[0].distance.value / 1000);

                    // add distance and store id to the array stores
                    stores.push({distance: response, id: item.properties.Nid});
                    responseCount++; //ADDED
                    sort_stores(stores, responseCount, totalCount); //ADDED Call sort function here
                }
            });
        });
    });
};
Sign up to request clarification or add additional context in comments.

19 Comments

I can call the add_stores_to_array().done(function() { anywhere, because of the .done(), right?
yes but I need to change the code a little bit, it does not seem to work.
$.when.apply(null, add_stores_to_array()).done(function() { from where I should call this function? See my fist post, edit 2 please.
ok can you also add console.log("store pushed") after stores.push({distance: response, id: item.properties.Nid});? is all done still the last message?
I have updated the answer. can you try the second approach?
|

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.