18

How can I control the move to next step according to the result of some ajax call?? the data.d returns with a bool value

$("#wizard").steps({
            onStepChanging: function (event, currentIndex, newIndex) {
                var move = false;
                if (currentIndex == 2) {
                    move = false;
                    $.ajax({
                        type: 'POST',
                        url: "Reservation.aspx/SomeFunction",
                        data: serializeData({  }),
                        contentType: "application/json",
                        dataType: 'json',
                        success: function (data) {
                            move = data.d;
                            return true;
                        },
                        error: ajaxLoadError
                    });
                }
                return move;
            },
            saveState: true

        });
Manolo
  • 16,729
  • 16
  • 67
  • 115
heeema
  • 193
  • 1
  • 1
  • 7
  • I haven't used jquery wizard steps but your problem happens because ajax gets called asynchronously. Check out another wizard plugin that accepts ajax loading (like: https://github.com/mstratman/jQuery-Smart-Wizard) – Gasim Nov 25 '13 at 21:11

10 Answers10

8
$.ajax({
    type: 'POST',
    url: "Reservation.aspx/SomeFunction",
    async: false,
    contentType: "application/json",
    dataType: 'json',
    success: function (data) {
       move = data.d;
       return true;
    },
    error: ajaxLoadError
});
Samuel
  • 1,976
  • 1
  • 15
  • 27
  • It seems that there is no way to make it work asynchronously, so I'll award you the bounty because it's the only way I found out to make it work. – Manolo Mar 16 '16 at 09:53
4

you can use Samy's approach with synchronous ajax request

$("#wizard").steps({
    onStepChanging: function (event, currentIndex, newIndex) {
        if (currentIndex == 2) {
            var requestResult = $.ajax({
                type: 'POST',
                url: "Reservation.aspx/SomeFunction",
                async: false,
                contentType: "application/json",
                dataType: 'json',
                error: ajaxLoadError
            });
            return requestResult.responseJSON.Result == "/*your expected value*/"
        }
    },
    saveState: true
});
AntonE
  • 592
  • 4
  • 13
4

If you don't want the $.ajax() function to return immediately, set the async option to false:

Set Timeout for Ajax if server not responding of your ajax call then it will move on next process.

$("#wizard").steps({
            onStepChanging: function (event, currentIndex, newIndex) {
                var move = false;
                if (currentIndex == 2) {
                    move = false;
                    $.ajax({
                        type: 'POST',
                        url: "Reservation.aspx/SomeFunction",
                        data: serializeData({  }),
                        contentType: "application/json",
                        dataType: 'json',
                        async: false,
                        cache: false,
                        timeout: 30000,
                        success: function (data) {
                            move = data.d;
                            return true;
                        },
                        error: ajaxLoadError
                    });
                }
                return move;
            },
            saveState: true

        });
Nirav Patel
  • 480
  • 4
  • 14
  • As I've said, "I'd want to know if there is any ASYNC approach". – Manolo Mar 11 '16 at 10:44
  • Yes I read that but, I forgot to mention that without ASYNC it's very difficult to handle that. It's possible with setTimeout(function () { " Your AJAX Code" }, 1000); but it's not secure way to handle. Above solution is secure and safe if you don't have any problem with ASYNC. – Nirav Patel Mar 11 '16 at 11:00
  • Did you get the help from above answer? – Nirav Patel Mar 13 '16 at 04:59
  • No, this is my actual approach. I'm looking for an async approach. However, I'm not sure if it's possible with this plugin. If not, I'll continue setting `async` to `false`. Anyway, the bounty is for the async approach. – Manolo Mar 13 '16 at 08:49
  • Look at @Samy answer. He's answering basically the same as you. – Manolo Mar 13 '16 at 08:50
  • Ok. Thanks for your help, but doesn't help at all, because this has been already answered. – Manolo Mar 13 '16 at 09:21
  • Async calls finish whenever they damn well please. You cannot control when an async call completes. You're trying to make an async call behave like a normal call, and that's not possible. Maybe you should re-evaluate your approach. Setting async to false or adding a timeout will give you what you want. – Ayush Sharma Mar 16 '16 at 06:41
4

I have the same problem, I was even thinking to use the "setStep" to force the steps after ajax load, then the latest version of the jquery.steps took out the "setStep"..

I end up by using the "next" method, and have to use a global trigger to stop the infinite loop for onChanging event, in short, I force the wizard go to next step if the ajax returns valid data, otherwise, it stays to the current step, here's the code

var $stopChanging = false; 

.... ....

onStepChanging: function (event, currentIndex, newIndex) {
      if ($stopChanging) {
        return true;
      } else {
        items = $.ajax({
        type: 'POST',
        url: "Reservation.aspx/SomeFunction",
        data: serializeData({  }),
        contentType: "application/json",
        dataType: 'json',
        success: function (data) {
            $stopChanging = true;
            wizard.steps("next");
        },
        error: ajaxLoadError
    });
   },
   onContentLoaded: function (event, currentIndex) {
       $stopChanging = false;
   }
}

The logic is like:

  1. Click "next" button to trigger onStepChanging
  2. By default, set the jquery.steps onStepChanging event returns false, then the $.ajax calls, if it returns the valid data (success), call jquery.steps to go to next step, and the onStepChanging triggers again, if it's not valid, do nothing, stay at current step

trigger two onStepChanging event every time does not sounds a good idea, but that's what I can have for now

You may need to add more conditions for different step index behaviors

Joe Lu
  • 1,608
  • 1
  • 11
  • 15
  • This doesn't look like a complete answer. – RBT Jan 15 '17 at 23:59
  • Guyz this is the real answer that is working nothing else.It took me 2 days to figure this answer out thanks man lots of time wasted on infinite loop everytime gets created..... – MR_AMDEV May 20 '19 at 01:30
3

I found another way how to solve this problem. OnStepChanging supports only boolean. There is pull request #232 which is adding usage of deffered object. (I found way how to use deffered object also on GitHub) I included this modified version to my project and used it in OnStepChanging like this:

    var def = $.Deferred();

    $.ajax({
        type: "POST",
        url: url,
        //async: false,
        beforeSend: function (xhr) {
            //ASP CORE Antiforgery token
            xhr.setRequestHeader("RequestVerificationToken",
                $('input:hidden[name="__RequestVerificationToken"]').val());
        },
        data: data,
        contentType: "application/json; charset=utf-8",
        dataType: "json",
        failure: function (xhr) {
            failureCallback(xhr);
        }
    }).done(function (response) {
        //Result of server validation
        var responseResult = response.result === "Success" ? true : false;
        // Check response
        def.resolve(responseResult);
        }).fail(function (response) {
            console.log(response);
            return false;
        });

    return def; // This is the Deferred that should be returned and NOT the one from jQuery Ajax

I hope this will help to someone else. :-)

2
$("#wizard").steps({
        onStepChanging: function (event, currentIndex, newIndex) {
            var $out= false;
            if (currentIndex == 2) {
                $out= false;
                $.ajax({
                    type: 'POST',
                    url: "Reservation.aspx/SomeFunction",
                    data: serializeData({  }),
                    contentType: "application/json",
                    dataType: 'json',
                    success: function (data) {
                        move = data.d;

                        $out = true;
                    },
                    error: ajaxLoadError
                });
            }
            return $out;
        },
        saveState: true

    });

Put global variable $out!

luisbg
  • 504
  • 4
  • 11
2

I encountered a similar problem, but i was using parsleyjs for validation. You might get an idea in my code.

My code is like this:

             onStepChanging: function (event, currentIndex, newIndex) {

                 // ======== Code that fails 

                 //var step = $wizard_advanced.find('.body.current').attr('data-step'),
                 //$current_step = $('.body[data-step=\"'+ step +'\"]');                        


                // check input fields for errors
                //$current_step.find('[data-parsley-id]').each(function() {
                    //this adds .md-input-danger to inputs if invalid
                    //there is remote validation occurring here via ajax
                    // async: false
                    //$(this).parsley().validate();
                //});

                // this is executed before ajax validation is finished 
                //return $current_step.find('.md-input-danger').length ? false : true;

                // ======== END of Code that fails 

                // FIX
                // waits on ajax validation to finish before returning
                if( $wizard_advanced_form.parsley().validate() ) {
                    return true;
                } else {
                    return false;
                }
                //FIX                    
            }
ambay
  • 307
  • 3
  • 8
2
var items;

$("#wizard").steps({
onStepChanging: function (event, currentIndex, newIndex) {
    var move = false;
    if (currentIndex == 2) {
        move = false;

        items = $.ajax({
            type: 'POST',
            url: "Reservation.aspx/SomeFunction",
            data: serializeData({  }),
            contentType: "application/json",
            dataType: 'json',
            success: function (data) {
                move = data.d;
                return true;
            },
            error: ajaxLoadError
        });


    }
    return move;
},
saveState: true

});



items.success(function (data) {
//if can log in go to logged in page
if (data.success == true) {
    alert("Working");
    var move = data.d;
    return true;

} else {
    alert("didnt work");
}
// output of data
alert(JSON.stringify(data));
});
Radmation
  • 1,262
  • 12
  • 24
2

Here's the only way I could get to work after several attempts this is what @joe-lu was getting at above. You just want to kick off the async call & return false. This will keep the wizard on the same step. THEN in the success handler you programmatically move to the next step.

$("#wizard").steps({
            onStepChanging: function (event, currentIndex, newIndex) {
                if (currentIndex == 2) {
                    //Would be a good idea to start a spinner here!
                    //would be a good idea to disable next button here!
                    $.ajax({
                        type: 'POST',
                        url: "Reservation.aspx/SomeFunction",
                        data: serializeData({  }),
                        contentType: "application/json",
                        dataType: 'json',
                        success: function (data) {
                            //stop spinner here!
                            //programmatically move to next step on success.
                            $("#wizard").steps("next");
                        },
                        error: ajaxLoadError
                    });
                }
                //Prevents natural movement to next step.
                //will be done programmatically
                return false;
            },
            saveState: true
        });
0
var is_async_step = false;
$("#wizard").steps({
        onStepChanging: function (event, currentIndex, newIndex) {
            //USED TO SEND USER TO NEXT STEP IS ASYNC REQUEST IS PRESENT - FOR AJAX CALL 
            if (is_async_step) {
                is_async_step = false;
                //ALLOW NEXT STEP
                return true;
            }

            if (currentIndex == 2) {                
                $.ajax({
                    type: 'POST',
                    url: "Reservation.aspx/SomeFunction",
                    data: serializeData({  }),
                    contentType: "application/json",
                    dataType: 'json',
                    success: function (data) {
                        move = data.d;

                        //Add below 2 lines for every Index(Steps).                            
                        is_async_step = true;
                        //This will move to next step.
                        $(form).steps("next");
                    },
                    error: ajaxLoadError
                });
            }
             //Return false to avoid to move to next step
             return false;
        },
        saveState: true
    });