jQuery wizard steps move before ajax call completed
Asked Answered
C

11

21

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

        });
Cholera answered 25/11, 2013 at 20:51 Comment(1)
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: github.com/mstratman/jQuery-Smart-Wizard)Jerk
E
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
});
Excrete answered 25/11, 2013 at 23:13 Comment(2)
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.Capricorn
using synchronous is very bad as it freezes the UI. actually there is away using deferred object. checkout this link: github.com/rstaib/jquery-steps/pull/232Neoteric
P
8

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

Pericope answered 15/1, 2017 at 23:35 Comment(2)
This doesn't look like a complete answer.Bochum
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.....Religious
C
5

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
});
Calfskin answered 24/6, 2015 at 15:59 Comment(0)
W
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

        });
Wystand answered 11/3, 2016 at 10:23 Comment(7)
As I've said, "I'd want to know if there is any ASYNC approach".Capricorn
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.Wystand
Did you get the help from above answer?Wystand
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.Capricorn
Look at @Samy answer. He's answering basically the same as you.Capricorn
Ok. Thanks for your help, but doesn't help at all, because this has been already answered.Capricorn
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.Phenomenology
A
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. :-)

Apostolate answered 13/2, 2019 at 7:55 Comment(0)
S
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!

Smelser answered 15/10, 2014 at 7:22 Comment(0)
R
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                    
            }
Reverie answered 20/1, 2016 at 13:37 Comment(0)
A
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));
});
Anthologize answered 15/3, 2016 at 15:54 Comment(0)
L
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
        });
Lyndseylyndsie answered 24/1, 2018 at 22:41 Comment(0)
P
1
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
    });
Pardue answered 5/7, 2018 at 12:17 Comment(0)
S
0

For avoiding to change step before ajax response , it should be notice some details. First, JQuery ajax is default asynchronous and it is natural that after request to controller by ajax , the Fuel UX Wizard don't wait for ajax response and do method procedural, then for waiting to ajax response it must use ajax setting "async:false". For using Fuel UX wizard and some methods in it for example on.('change'), we notice that when moving in steps for avoiding or continuing move in steps, we must return true or false for result object that it can understand move or not. In my sample, I used a variable for return true or false after ajax method that I called "stepState". See my example it worked for me :

$('#fuelux-wizard').ace_wizard().on('change', function (e, info) {
                if (info.step == 1) {
                    if ($('#ConfirmFirstStepInfo').is(':checked')) {
                        return true;
                    }
                    else {
                        return false;
                    }
                } else if (info.step == 2) {
                    if ($('#ConfirmSecondStepInfo').is(':checked')) {
                        var ourObject = {};

                        var stepState = null;
                        $.ajax({
                            type: 'POST',
                            data: ourObject,
                            async: false,
                            contentType: false,
                            processData: false,
                            cache: false,
                            url: '/Controller/Action',
                            success: function (response) {
                                if (response.Success == true) {

                                    stepState = true;
                                    return true;
                                }
                                else {

                                    stepState = false;
                                    return false;
                                }
                            },
                            error: function () {

                                stepState = false;
                                return false;
                            },
                            failure: function () {

                                stepState = false;
                                return false;
                            }
                        });

                        return stepState;
                    }
                    else {

                        return false;
                    }
                } else if (info.step == 3) {
                    if (!$('#validation-form').valid()) 
                    { 
                        return false; 
                    }else{
                        return true; 
                    }
                }
        }).on('finished', function (e) {
            alert('finished!');
        }).on('btn-wizard-next', function (e) {
            //return false;//prevent clicking on steps
            //e.preventDefault();//this will prevent clicking and selecting steps
        });
Saucepan answered 23/9, 2021 at 11:16 Comment(0)

© 2022 - 2024 — McMap. All rights reserved.