0

I seem to be running into the typical "Asynchronous Problem", with the solution eluding me.

I have a bootstrap form wizard which is just an improvised tabs/slideshow kinda thingy. All my "Steps" are forms each inside respective tabs/slides.

It has a set of next/previous buttons to navigate around the slides. And It provides a function callback on before moving to next slide. Inside which(callback) I am "client-side validating" the form in current slide and if its validated then I am submitting the form using ajax. And once I get the response from server, I am deciding whether to return true (proceed to next slide) or return false (stop the navigation to next slide).

I have looked into ..

  • Using callbacks but then it wont stop the plugin from proceeding to next slide, which btw is a hard coded success message, so while we are waiting for the ajax response the wizard has already moved to the next slide.
  • Using async:false but this hangs the browser like crazy(by design), till the request is completed, so sans the hanging this is exactly what I want.

My code is as below.

JS.

  jQuery('#progressWizard').bootstrapWizard({
            'nextSelector': '.next',
            'previousSelector': '.previous',
            onNext: function (tab, navigation, index) {
                if (index == 1) { // Here I am deciding which code to execute based on the current slide/tab (index)
                    if (jQuery("#paymentstep1").data('bValidator').validate()) {
                        var data = new FormData(jQuery('#paymentstep1')[0]);
                        jQuery("#cgloader").fadeIn();
                        var success = false;
                        jQuery.ajax({
                            type: "post",
                            async: false,
                            contentType: false,
                            processData: false,
                            url: "xyz.php",
                            dataType: "json",
                            data: data,
                            success: function (r) {

                              return r;
                            }
                          });
                        }....
Community
  • 1
  • 1
Mohd Abdul Mujib
  • 13,071
  • 8
  • 64
  • 88
  • The first method is the only real acceptable solution. If that means changing the wizard plugin I would still highly recommend it. Using `async: false` is never an option because as you've seen, it hangs the browser until the request completes. This will make the browser look to the user like it crashed which is terrible UX. The workaround for this is to use an async request. – Rory McCrossan May 12 '16 at 15:03
  • Stop the navigation to the next slide then re-start it on callback – Jonathan Gray May 12 '16 at 15:03

3 Answers3

3

The docs for onNext say:

Fired when next button is clicked (return false to disable moving to the next step)

So simply return false from your handler. In the AJAX success callback, call next to advance to the next slide.

var requestCompleted = false;
jQuery('#progressWizard').bootstrapWizard({
  'nextSelector': '.next',
  'previousSelector': '.previous',
  onNext: function (tab, navigation, index) {
    if (index == 1) { // Here I am deciding which code to execute based on the current slide/tab (index)
      if (jQuery("#paymentstep1").data('bValidator').validate()) {
        if(!requestCompleted) {
          var data = new FormData(jQuery('#paymentstep1')[0]);
          jQuery("#cgloader").fadeIn();
          var success = false;
          jQuery.ajax({
              type: "post",
              url: "xyz.php",
              data: data,
              // ...
              success: function (r) {
                requestCompleted = true;
                jQuery('#progressWizard').bootstrapWizard('next');
                return r;
              }
            });
          return false;
        }
      }
    }
  });
Dark Falcon
  • 43,592
  • 5
  • 83
  • 98
  • But then if I call the next inside ajax success, won't the code inside the "onNext " callback be triggered all over again?? Making the ajax request again? – Mohd Abdul Mujib May 12 '16 at 15:05
  • Sure. So use a variable to track whether you've made the request yet or not. – Dark Falcon May 12 '16 at 15:10
  • hm... tbh, I had this in mind all the way, but was unsure if it was the right way to go, so I'll keep this as the last resort if I dont find a better solution. Thanks. – Mohd Abdul Mujib May 12 '16 at 15:11
2

Use a promise?

There is a promise in jQuery. Here is the Syntax.

$.when( $.ajax( "test.aspx" ) ).then(function( data, textStatus, jqXHR ) {
  alert( jqXHR.status );    });

There are also now promises in javascript!

var promise = new RSVP.Promise(function(fulfill, reject) {
  (...)
});

Then,

promise.then(onFulfilled, onRejected);
Chris Clark
  • 387
  • 1
  • 14
1

I would use different events to execute your async code. The idea is to use onTabChange ( consider using onTabClick and onTabShow ) so you prevent moving to the next tab how bootstrapWizard(); would navigate. Only after everything passed fire the next tab programmatically, which you have to find out how.

$('element').bootstrapWizard('onTabShow', function(){

  //Do everything you need here and show next tab
  $('element').bootstrapWizard('show',3);
  return false;
});
Rosmarine Popcorn
  • 10,761
  • 11
  • 59
  • 89