Hi

My issue is that I want to either call 2 AJAX functions one after the other OR call just the second one.

Let me put this into context.. I am writing a "store locator" application. By default all the results are loaded in alphabetical order. A user is able to enter their address or postcode into a box and hit search. My application will then find their latitude and longitude coordinates from their input using Google's geocoding API and then pass these coordinates into my own AJAX call which will then order the results based on their location, closest store first.

However, if the user does not enter a postcode I want to just go back to the default and show the results in alphabetical order once again.

So far...

    function generateResults(_postcode) {
        //console.log("generating results");
        if (readyState) {
            changeReadyState(false); // Changes the state of the application, lays a translucent DIV on top of the controls and only allows single execution of this function
            jQuery.ajax({
                url: "http://maps.googleapis.com/maps/api/geocode/json?address=" + encodeURIComponent(_postcode) + ",UK&sensor=false",
                success: function(d){
                    var _u = ajax_url;

                    if (d.results && d.results[0] && d.results[0].geometry && d.results[0].geometry.location) {
                        var location = d.results[0].geometry.location;
                        _u = appendQS(_u, "lat=" + location.lat); // Appends as query string, putting either ? or & before
                        _u = appendQS(_u, "lng=" + location.lat);

                        jQuery.ajax({
                            url: _u,
                            success: function(data){

                                changeReadyState(true);
                            },
                            error: function(){
                                changeReadyState(true);
                            },
                            async: false
                        });
                    }
                    else if (d.error_message) {
                        alert(d.error_message);
                        changeReadyState(true);
                    }
                    else {
                        alert("No results found for '" + _postcode + "'");
                        postcodeTxt.val("");
                        changeReadyState(true);
                    }

                },
                error: function(){
                    changeReadyState(true);
                }
            });
        }
        else {
            //console.log("Application busy, try again soon");
        }
    }

I suppose I could just have two cases depending on whether the _postcode is empty or not but this would mean repeating code.

Basically I want to only call the Google Geocoding API if the _postcode field is not empty, but I want to ensure that this call is either not going ahead or has finished before I call my own AJAX.

I had a look at making the first request synchronous but according to the jQuery docs, it's been deprecated and they recommend using their success/error/complete callbacks instead.

I've a feeling it's just a bit late in the day!

Cheers

Recommended Answers

All 5 Replies

What event triggers going back to the alphabetical list if no postcode is entered?
If the results are showing alphabetically by default, if the entered postcode does not result in a location, then you needn't do anything?
May not be helpful:(If you want to avoid duplicating code, create a function and call it instead of using inline functions.)
I know you didn't want to post too much code but it's difficult to get the overall flow from this one function.

First, simplify the main function by pulling out the two ajax calls into their own functions as follows:

function fetch_1(_postcode) {
    return $.ajax({
        url: 'http://maps.googleapis.com/maps/api/geocode/json',
        data: {
            address: encodeURIComponent(_postcode) + ',UK',
            sensor: 'false'
        }
    });
}
function fetch_2(location) {
    location = location || {lat:0, lng:0};//null geo-location, to be handled server-side as a special case.
    return $.ajax({
        url: ajax_url,
        data: {
            lat: location.lat,
            lng: location.lng
        }
    }).done(function(data) {
        //display stores data here
        display_stores(data);//for example
    }).fail(function(jqXHR, textStatus, errorThrown) {
        //handle failure case here
        clear_stores();//for example
    }).always(function() {
        changeReadyState(true);
    });
}

Note how in fetch_2(), a null or undefined location defaults to {lat:0, lng:0}, which then needs to be handled as a special case server-side (ie geo sort not required). fetch_2() also has its own .done and .fail handlers, to avoid repetition inside generateResults().

Now generateResults() can be simplified to call fetch_1() and fetch_2(), and modified such that the parameter passed to fetch_2() is either a taken from a successful fetch_1() or null in the various cases where no postcode geolocation is available.

function generateResults(_postcode) {
    //console.log("generating results");
    if (readyState) {
        changeReadyState(false); // Changes the state of the application, lays a translucent DIV on top of the controls and only allows single execution of this function
        fetch_1(_postcode).then(function(d) {
            var loc = null;
            if (d.results && d.results[0] && d.results[0].geometry && d.results[0].geometry.location) {
                loc = d.results[0].geometry.location);
            }
            else if (d.error_message) {
                alert(d.error_message);
            }
            else {
                alert("No results found for '" + _postcode + "'");
                postcodeTxt.val("");
            }
            fetch_2(loc);
        }, function(jqXHR, textStatus, errorThrown) {
            fetch_2(null);
        });
    }
    else {
        //console.log("Application busy, try again soon");
    }
}

fetch_2() is thus called regardless of the success/failure of fetch_1(). The .done() handler inside fetch_2() displays the Stores (sorted alphabetically or in geo-order, as determined server-side); its .fail() handler clears the stores list (or whatever); and its .always() handler reverts the user interface to the normal state.

This strategy should maximise the chance of obtaining results, and in any circumstance other than an uncaught javascript error, the interface should revert.

... then, to answer the actual question ...

When _postcode is blank, you can avoid relying on the Google geocode call to tell you whast you already know - ie there will be no results.

This can be achieved by modifying fetch_1 as follows :

function fetch_1(_postcode) {
    if(_postcode) {
        return $.ajax({
            url: 'http://maps.googleapis.com/maps/api/geocode/json',
            data: {
                address: encodeURIComponent(_postcode) + ',UK',
                sensor: 'false'
            }
        });
    }
    else {
        return $.Deferred().resolve(null).promise();
    }
}

fetch_2(), as already written, will detect the null and cause the Stores to be listed alphabetically.

Thanks a lot for the detailed answer. It was really helpful to study your approach to it and makes sense. However, I eventually rolled everything into a single AJAX call and just used PHP's file_get_contents() function to use Google's Geocoding service.

Thanks again.

OK Bops, that is also a perfectly valid approach, just not as much fun if you like client-side coding.

Be a part of the DaniWeb community

We're a friendly, industry-focused community of developers, IT pros, digital marketers, and technology enthusiasts meeting, networking, learning, and sharing knowledge.