1

Here is my (simple) problem :

I have a Javascript function which calls an external API in order to get some result asynchronously. I need to wait these results because I want to do some tests on them to determine if they are valid or not, but Deferred are very complex to me and I can't success.

Here is what I've done :

$("#step-content").steps({
    //some parameters
    onStepChanging: function(event, currentIndex, newIndex) {
        verifyAddress().done(function(test) {
            if($("#hdnLatitude").val() == "" || $("#hdnLongitude").val() == "")
                test = false;
            else
                test = true;

            console.log(test); // test is true or false, that's good
            return test;
        });

        console.log(test); // test is always empty here

        //Here, I just need to do return true or return false to block step-changing if there is an error.
        return test;
    }
});

Basically, here is my verifyAddress function :

function verifyAddress() {
    var r = $.Deferred();

    var geocoder = new google.maps.Geocoder();
        if (geocoder) {
            var adressToGeocode = /* Get the address to geocode */

            geocoder.geocode({ 'address': adressToGeocode }, function (results, status) {
                if (status == google.maps.GeocoderStatus.OK) 
                {
                    //Save the lat/lng returned in #hdnLatitude and #hdnLongitude
                }

                r.resolve();
            });
        }
    //Not sure where to place the return r ; try elsewhere but no success
    return r;
}

So what I need is wait for the end of verifyAdress() and get the #hdnLatitude and #hdnLongitude filled, and return true of false in onStepChanging event to determine if we can go to next step (address is OK) and not (address is wrong)

I'm using this SO question to better understand Deferred, but I can't success.
Is anyone able to help me ?

Thanks a lot

Community
  • 1
  • 1
AlexB
  • 7,302
  • 12
  • 56
  • 74
  • How to return from asynchronous function. Classics. Take a look [here](http://stackoverflow.com/questions/14220321/how-to-return-the-response-from-an-ajax-call) to understand why you can't do it. – dfsq Sep 20 '14 at 14:04
  • HI. I know this is a classic problem for a beginner like me, but I really need help to understand the problem. I've seen this link, do I have to pass a callback to my `verifyAddress()` method ? I can't understand the underlying logic... – AlexB Sep 20 '14 at 14:09
  • If possible, can post `html` , "call Google server" portions ? Thanks – guest271314 Sep 20 '14 at 14:32
  • 1
    @guest271314: Have a look at [this question](https://stackoverflow.com/questions/6847697/how-to-return-value-from-an-asynchronous-callback-function) for an example. Whether you take callbacks or return deferreds doesn't make a difference, you cannot synchronously `return true/false` from the `onStepChanging` method. – Bergi Sep 20 '14 at 14:39
  • @Bergi Why can't I return true/false from the `onStepChanging` method ? It "just" has to call `verifyAddress()`, which call an asynchronous function, then wait for the result... Is it really "impossible" ?? Could you suggest something which resolve my problem ? – AlexB Sep 20 '14 at 14:48
  • @Bergi Not tried "geocode" . Thanks for sharing link ! – guest271314 Sep 20 '14 at 15:02
  • 1
    @AlexB: Yes, it's really impossible. You cannot busy-wait for an asynchronous result. The solution of your problem is too choose a different `steps` plugin, one that can cope with asynchronous functions. – Bergi Sep 20 '14 at 15:06
  • 1
    Here is another question which explains the asynchronous nature: https://stackoverflow.com/questions/23667086/why-is-my-variable-unaltered-after-i-modify-it-inside-of-a-function-asynchron . The problem is that you are using a third party library which expects the code to be synchronous. You can't use asynchronous code when synchronous code is expected. As Bergi said, you need to find another plugin. – Felix Kling Sep 20 '14 at 16:04
  • @FelixKling: There is a workaround. Someone else asked this question last week and I answered that. Let me see if I can find it. The workaround is basically do all your async stuff and store the results first before running synchronous code. – slebetman Sep 20 '14 at 23:15
  • A workaround to this problem can be found here: http://stackoverflow.com/questions/25756226/waiting-for-ajax-response-same-function/25778406#25778406. It's not an exact duplicate to this question because it looks like a different plugin but it's basically the same underlying issue - how to get pass async data to sync functions. – slebetman Sep 20 '14 at 23:19

2 Answers2

1

You function should look like:

function verifyAddress() {
    var r = $.Deferred();

    //call Google server to geocode my address. The call is asynchrounous.
    //The results are put in #hdnLatitude and #hdnLongitude fields.
    //The fields are correctly filled.
    googleFunc(someParam, function done(){
      r.resolve();
    });

    return r;
}

You have to resolve deferred inside some done callback that will be called by Google server function, there must some callback function for processing results.

var test = false; //Can't change step until allowed in async function   
$("#step-content").steps({
    //some parameters
    onStepChanging: function(event, currentIndex, newIndex) {
    if (!test)
      verifyAddress().done(function() {
            if($("#hdnLatitude").val() == "" || $("#hdnLongitude").val() == "")
                test = false;
            else
                test = true;

            console.log(test); // test is true or false, that's good

            //Auto move to next step if test is true
        });


        //Here, I just need to do return true or return false to block step-changing if there is an error.
        return test;
    }
});
VitaliyG
  • 1,837
  • 1
  • 11
  • 11
  • Please take a look to my updated question. It seems to me this is what I've done ; however, this doesn't work ? Could you point me out where I'm wrong ? – AlexB Sep 20 '14 at 14:59
  • @VitaliyG: Your updated code doesn't seem to work. You cannot assign to `test` in an *asynchronous* callback, and then [expect it to be set when you `return`](https://stackoverflow.com/questions/23667086/why-is-my-variable-undefined-after-i-modify-it-inside-of-a-function). – Bergi Sep 20 '14 at 15:39
  • Stepping must be done twice, once to start async function, and once after it is completed. Second time it can be initiated from async callback. – VitaliyG Sep 20 '14 at 16:23
  • I'm probably missing something, but test is always false as it gloablly defined, even when it should be true... – AlexB Sep 20 '14 at 16:57
  • @AlexB: When verifyAddress is done - in the future, not at the time you 're checking for it in the code. You can verify this if you have a javascript console and when verifyAddress completes manually enter `alert(test)` by hand in the console to inspect the value. – slebetman Sep 20 '14 at 23:22
  • @slebetman yes this could be a solution. This problem is not "blocking" as it is a personal project, but I love clean and proper code, so I'll probably do something like this and modify my UX reluctantly – AlexB Sep 21 '14 at 12:54
0

Ok, as @Bergi said, this seems impossible with this plugin.

So, I bypassed the problem, replacing the Next button by a fake which call my asynchronous event. At the end of this event, if the result is OK, I replace the Next button by the orignal one I cloned and trigger a click event on it to pass to the next step without the user had to click twice.

Don't know if it's really clean, but it works for my needs

AlexB
  • 7,302
  • 12
  • 56
  • 74