How can I gracefully interrupt an AJAX callback? I have a form element that triggers an AJAX callback call when it looses focus.  This callback can take a few seconds, which generally is not an issue.

If a user submits the form before the AJAX callback completes, the following error is displayed:

Here is the exact error message displayed to the end user:


  An AJAX HTTP request terminated abnormally.Debugging information
  follows.Path: /system/ajaxStatusText: ResponseText: ReadyState: 4


How can I gracefully terminate an AJAX callback from completing when passing control to a submit handler?

This is the relevant code from the module.

function a_custom_form($form, &amp;$form_state) {
  $form['email'] = array(
    '#prefix' =&gt; '&lt;div id="cust-email"&gt;',
    '#suffix' =&gt; '&lt;/div&gt;',
    '#type' =&gt; 'textfield',
    '#title' =&gt; t('Customer Email Address'),
    '#required' =&gt; TRUE,
    '#ajax' =&gt; array(
      'callback' =&gt; '_user_email_ajax',
      'wrapper' =&gt; 'cust-email',
      'effect' =&gt; 'fade',
    ),
  );
  $form['submit'] = array(
    '#type' =&gt; 'submit',
    '#value' =&gt; t('Submit Request'),
  );

  return $form;
}

function _user_email_ajax($form, &amp;$form_state) {
  $commands = array();
  // Doing time intensive stuff here...
  drupal_set_message(t('Some Message'), 'error');
  $commands[] = ajax_command_replace('#email-warning-message', '&lt;div id="email-warning-message"&gt;'. theme('status_messages') . '&lt;/div&gt;');

  return array(
    '#type' =&gt; 'ajax',
    '#commands' =&gt; $commands,
  );

}


I have tried the solution given for Prevent &quot;AJAX HTTP request terminated&quot; error on early form submit, but this seems to prevent the submit button from functioning, rather than interrupting the AJAX callback.
That's not directly possible. There is no API in the browser to manually cancel a sent request. All you can do is to register a callback to know when the HTTP response is received, or at least when the browser changes the state on the xmlHttpRequest object. Drupal's AJAX code already handles that for you. The error message you're seeing is shown because another request was sent which did interrupt the background request, but that still looked as if it was completed (readyState == 4). Drupal considers completely empty responses to be an error and the message is shown.

The most common and user friendly approach I've seen is indeed to disable the submit button(s) while a request is in progress. That in combination with a "spinner" animation or progressbar is a good indication that the user should keep waiting and that they will benefit from it. When the request completes (failed or successful), the buttons are unlocked again.

An input field can become unfocused at any time and for different reasons (maybe the user just wants to copy/paste something into it really quick). Triggering a long running background request whenever that happens could quickly become annoying. As you've already noticed, it interferes with the normal form submit flow as well. Maybe you can work around that and trigger the requests by some other means which more clearly indicate to the user that they need to wait for it to complete? Perhaps giving them the choice to initiate the request when they're sure to be done with manual input into the field and are more inclined to wait for automated processing of their input. Or perhaps trigger the request after a short timer which gets stopped when the field is refocused or the form is submitted.

If not, you could try overriding Drupal's AJAX response interpreting code so it won't show that message if the submit button interrupts the background request, first setting some flag to indicate AJAX errors are to be ignored. Whether this works also depends on how important it is that the AJAX operation on your field completed. If it performs some kind of correction on the [email address?] the user entered, they get it wrong, but the correcting routine didn't get a chance to update the field with valid input, this probably means your serverside validation fails and the user needs to submit it again - which could have been avoided if they had waited for the request to complete.