views:

539

answers:

5

Following on from a previous question where I asked about disabling a submit button until all ajax calls have finished returning...

It seems that people are still managing to submit the form even with the button disabled and a warning sign. I guess it could be from pressing 'enter' in a text input.

How do I go about disabling the whole form, rather than just the submit button?

The code so far is:

// if we're waiting for any ajax to complete we need to disable the submit
$(document).ajaxStart(function() {
  $(".ajaxbutton").attr("disabled", "disabled");
  // if it's taken longer than 250ms display waiting message
  timer = setTimeout(function() {
    $('#processingAlert').html(' ...please wait one moment');
    $('#processingAlert').show();
  }, 250);
})
$(document).ajaxComplete(function() {
  $(".ajaxbutton").removeAttr("disabled");
    $('#processingAlert').hide();
    // cancel showing the message when the ajax call completes.
clearTimeout(timer);
});

One other thing that I should mention which could be causing a problem is that there are multiple ajax calls happening at the same time, EG one div receives hidden inputs and another div elsewhere on the page shows a price total for instance.

Would the fact that some ajax calls are completing quickly negate the disabling effect of ajaxStart? EG ajax call1 and ajax call2 both fire the ajaxStart - call1 finishes really quickly, would it re-enable the form while we are waiting for call2 to complete?

Is there a better way of doing this where we could simply test if ALL ajax calls have completed?

+1  A: 

You can add an event handler for the submit event of the form. The event handler can check if the submit is allowable yet, and abort if not. Here's some docs: http://api.jquery.com/submit/

Note that if javascript on the page calls .click() on one of the form submission buttons, the form will be submitted without calling your .submit() handler. This is a weird jQuery issue (http://groups.google.com/group/jquery-en/browse_thread/thread/1317bfd4e3a8b233?pli=1) which I guess the jQuery folks don't consider a bug. There may be other cases like this, I hope not.

If you're using ASP.NET, depending on whats on the form, ASP.NET may inject a "__doPostBack" function. You may need to hook that function instead by redefining it with some custom code that calls the original.

Frank Schwieterman
This sounds along the right lines, from the manual: $("form").submit(function() { if ($("input:first").val() == "correct") { $("span").text("Validated...").show(); return true; } $("span").text("Not valid!").show().fadeOut(1000); return false; });So if I check that all ajax calls are completed I can return true.I'm using PHP so, can't use the ASP functions unfortunately.
Ashley
PS Can anyone let me know how to insert code formatted into a comment, I always seem to get everything squished onto one line
Ashley
I don't think you can format code in comments. I'd go ahead and extend your question with additional comments.
Frank Schwieterman
A: 

How about creating a global variable:

  var i = 0;

and each AJAX call increments this variable at the start of the call and decrements it when complete.

On submit of the form, check if this variable is greater than 0 and prevent the submit.

  function submitForm(){
      return i == 0;
  }

<form onsubmit="submitForm()"....>

</form>
Vincent Ramdhanie
This sounds quite versatile. At which points in the ajax call do we increment / decrement. Is the increment right after $.ajax({
Ashley
I would imagine that you increment at the start of the ajaxStart function and decrement at the start of the ajaxComplete function
Vincent Ramdhanie
this seemed like a good idea, but when I tried it, all 3 ajax calls start simultaneously and the counter gets a value of 1. Then when they complete at different times, the counter goes to -2.
Ashley
+1  A: 

You could just set a JS object with multiple properties for each ajax call. Example:

var requiredCalls = {call1: false, call2: false, call3: false}

On form submit loop through each property to check for true. If any are false do not submit the form.

As each ajax call completes set its property (call1, call2, etc) to true.

Thats one way you could do it, whether its the best way, I don't know.

Mark
This sounds like a good idea, however there are several different calls which can be possibly made on this page, not all of them are triggered by each customer. I will have a think.
Ashley
in that case, if i understand you correctly, you would set their defaults to true. When the ajax call is triggered you would set its property in requiredCalls to false and oncomplete/onsuccess you would set it back to true.
Mark
A: 

I guess you have some code like this:

var form = $(...);
form.bind ('submit', function (...) {
  $.ajax (
    ...,
    complete: function (...) {
      // do something
    }
  );
}

you can do that:

var form = $(...);
form.bind ('submit', function (...) {
  if ($ (this).data ('inprogress') === null) {
    $ (this).data ('inprogress', 1);
    // disable submit button
    $.ajax (
      ...,
      complete: function (...) {
        // do something
        $ (this).data ('inprogress', null)
        // enable submit button
      }
    );
  } else {
    // display notification / warning
  }
}
mathroc
A: 

I've nearly solved this but somehow people seem to still be able to submit the form before the callbacks have finished.

I don't know if it's coincidence but all the people who have managed to submit it have been using Safari on Mac.

Here's the method I am using, would be great if anyone could spot the flaw in the logic.

Using Vincent's suggestion:

// set this to zero before any ajax calls are made  
var ajaxcallcounter = 0;

then when I do an ajax call for instance:

    // UPDATE SHIPPING BOXES
    var data = 'pickup=1';
    ajaxcallcounter++;
    $.ajax({
    type: "POST",
    url: "incViewbasketShippingBoxes.php", 
    data: data,
    success: function(response) {
        $('#shippingBoxes').html(response);
            ajaxcallcounter--;
    }
    });

This is working fine, I also have a nice little script to give user feedback - button is greyed out while waiting for ajaxcounters to return and if it takes longer than 250ms, an animation is displayed too. Once all ajax calls have completed, the counter is back to zero and the button is displayed as normal:

// when ajaxStart is triggered, keep an eye on the ajaxcallcounter
$(document).ajaxStart(function() {
  $(".ajaxbutton").attr("disabled", "disabled");
  $('#processingAlert').html(' ...calculating');
  $('#processingAlert').show();

  // if it's taken longer than 250ms (say) display waiting message
  timer = setTimeout(function() {
    $('#processingAlert').html(' ...calculating <img src="../gfx-site/ajax-loader.gif">');
  }, 250);
});
// when ajaxComplete is triggered, keep an eye on the ajaxcallcounter
$(document).ajaxComplete(function() {
    if (ajaxcallcounter == 0) {
        $(".ajaxbutton").removeAttr("disabled");
        $('#processingAlert').hide();
        // cancel showing the message when the ajax call completes.
    clearTimeout(timer);
    }
});

Finally, we come to the function which should prevent submission, but doesn't seem to be working:

// can we submit yet?
  $('#checkoutform').submit(function() {
    if (ajaxcallcounter == 0) {
      return true;
    }
    return false;
  });

Can anybody spot what I have done wrong here?

Thanks!

Ashley