0

I have a function to get a users lat long. I need to get that to return a url based on users location the url will differ. The returned url is used in a ajax call. However this second ajax call is getting hit before my first function finishes which then gives a 404 as the url is undefined.

so my code is:

$(document).ready(function () {
   getLatLong();

   if (!hasTicket) {
        doAction();
    } else {
        doAnotherAction();
        $.unblockUI();
    }
});

function doAction() {
         $.ajax({
            url: url, // this is where I am failing
            type: 'POST',
            success: function (response) {
                ticket = response.data.ticket;
                $.unblockUI();
            },
            error: function (xhr) {
                $.unblockUI();
                errorHandler("Failed" + xhr.status);
            }
        });
}

function getLatLong() {
    if (Modernizr.geolocation) {
        navigator.geolocation.getCurrentPosition(
            function (position) {
                getUrl(position.coords.latitude, position.coords.longitude);
            },
            getUrlFallback,
            { enableHighAccuracy: false, timeout: 10000, maximumAge: 360000 }
        );
    } else {
        getUrlFallback();
    }
}

function getUrl(latitude, longitude) {
    $.ajax({
        url: 'api/Controller/Action',
        type: 'GET',
        async: false, // tried making this synchronous
        data: {
            latitude: latitude,
            longitude: longitude
        },
        success: function (data) {
            url = data;
        },
        error: function (xhr) {
            errorHandler("Failed to get users nearest url: " + xhr.status);
        }
    });
}

So I call getLatLong which then calls my getUrl ajax function which has async set to false however I think it is returning from getLatLong first as my doAction function gets called and the url is then getting undefined.

How can I ensure that getLatLong and getUrl fully finish before the doAction gets run?

I tried to copy the functionality which happens after the call to getLatLong(); into a function and using $.when adn .then as below but it is still getting into the doAction method before the url is getting set.

function callAction() {
       if (!hasTicket) {
            doAction();
        } else {
            doAnotherAction();
            $.unblockUI();
        }
}

and then I had the below in doc ready:

$(document).ready(function () {

    $.when(getLatLong()).then(callAction());
});

EDIT - updated with the getUrlFallback function

function getUrlFallback () {
    // uses 3rd party geoPlugin
    getUrl(geoplugin_latitude(), geoplugin_longitude());
}
7
  • 2
    You need to stop the Ajax Async, . stackoverflow.com/questions/1478295/… or you could call the second function inside the success: function(data) of first Ajax Function Commented Jan 8, 2015 at 14:27
  • 3
    I wouldn't say he needs to 'stop the async', but instead change his pattern to use it effectively. Commented Jan 8, 2015 at 14:29
  • @DawoodAwan no, going synchronous is not the right answer! Commented Jan 8, 2015 at 14:30
  • Please show (at least some of) the getUrlFallback function too. Commented Jan 8, 2015 at 14:33
  • 1
    @DawoodAwan asynch: false is a terrible suggestion. DO NOT USE this Commented Jan 8, 2015 at 14:34

1 Answer 1

1

You can convert your getLatLong call to return a jQuery Promise:

(NB: I'm not including the getUrlFallback logic here as you haven't included that code so I can't tell what its supposed to do):

function getLatLong() {
    return $.Deferred(function(def) {
         if (!Modernizr.geolocation) {
             def.resolve(geoplugin_latitude(), geoplugin_longitude());
         } else {
             navigator.geolocation.getCurrentPosition(
                 function(position) {
                     def.resolve(position.coords.latitude, position.coords.longitude);
                 },
                 def.resolve(geoplugin_latitude(), geopugin_longitude()),
                 { enableHighAccuracy: false, timeout: 10000, maximumAge: 360000 }
             );
         }
    }).promise();
}

And also modify getUrl such that it returns the result of $.ajax, and omitting the success and error callbacks:

function getUrl(latitude, longitude) {
    return $.ajax(...);
}

So you can now use:

getLatLong().then(getUrl).then(callAction);   // NB: no () after callAction

callAction will automatically be passed the URL, instead of it being stored in a variable in the outer scope.

Note now how the getLatLong function specifically now does that and only that. It doesn't subsequently try to convert the lat/long into a URL because getUrl does that for you (whether the URL came from the GeoAPI or the geoplugin).

Sign up to request clarification or add additional context in comments.

8 Comments

I have updtaed with the getUrlFallback function - would you be able to Edit your answer as to how this should look now in the prmoises function
and where you have showed in getUrl to return $.ajax should I remove the async :false?
@TheRiddler yes - definitely remove the async: false - I didn't stop that in your own code. I'll take a look at the getUrlFallback bit
@TheRiddler is the getNearestUrl function also async?
no that was an old copy I copied - it should just call getUrl
|

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.