1

I'm disabling a button before every ajax call, and re-enabling it once the call is compete. I'm doing this like:

jQuery.fn.buttonDisable = function(v) {

    if(v)
        $(this).prop('disabled', true).addClass('animate-load').parents('html').addClass('busy');
    else
        $(this).prop('disabled', false).removeClass('animate-load').parents('html').removeClass('busy');

};


$('.element button').buttonDisable(true);

$.ajax({
    type: "post",
    dataType: "json",
    url: "/api/login",
    data: {
        username :  username.val(),
        password : password.val(),
    }
})
.done(function(data) {

    $('.element button').buttonDisable(false);

    ...

Would it be possible to pass a parameter into the ajax function and have this automated? Something like:

$.ajax({
    button: $('.element button'),

    ...

So this would run the following before the ajax call starts:

    $('.element button').prop('disabled', true).addClass('animate-load').parents('html').addClass('busy');

And once complete, run:

    $('.element button').prop('disabled', false).removeClass('animate-load').parents('html').removeClass('busy');
3
  • 2
    not quite what youve asked for but this also works: api.jquery.com/ajaxStart Commented Mar 23, 2015 at 14:03
  • I'm wanting to write the button disable and enable just once, and have it work any time I use a specific setting on an ajax function. Commented Mar 23, 2015 at 14:06
  • Also api.jquery.com/ajaxComplete Commented Mar 23, 2015 at 14:07

4 Answers 4

1

Either of the other listed methods (.ajaxStart or $.ajaxSetup) will work fine to "globally" enhance ajax with that functionality, however I would suggest against this. EVERY call to $.ajax will get passed through those methods, including calls done by third party libraries. This might not be the desired behavior in the end.

If this were for any "large" project I would write my own $.ajax method that could be used anywhere I wanted that functionality, something like this:

(function ( $ ) {
  var root = $('html');

  function doAjax(options) {
    var jqXHR = $.ajax(options);

    if (options.disableSelection) {
      root.addClass('busy');
      options.disableSelection
        .prop('disabled', true).addClass('animate-load')

      jqXHR.always(function() {
        root.removeClass('busy');
        options.disableSelection
          .prop('disabled', false).removeClass('animate-load');
      });
    }

    return jqXHR;
  }

  window.doAjax = doAjax;
})(jQuery);

You can then replace $.ajax call that you want to have that functionality with doAjax instead of $.ajax and pass in your disableSelection: $('.element button').

You also get passed the options in the jQuery global events (.ajaxComplete and .ajaxStart) as well as in the beforeSend and complete as this if you take the $.ajaxSetup route.

Also, maybe take a look at $.ajaxPrefilter you get access to everything in there.

(function ($) {
  // this value will never change, so why bother looking it up more than once
  var root = $('html'); 

  // we get to check the options of every $.ajax call, awesome!
  $.ajaxPrefilter(function(options, originalOptions, jqXHR) {

    if (options.disableSelection) {

      root.addClass('busy');
      options.disableSelection
        .prop('disabled', true).addClass('animate-load');

      jqXHR.always(function() {
        root.removeClass('busy');
        options.disableSelection
          .prop('disabled', false).removeClass('animate-load');
      });
    }

  });
})(jQuery);

// and then somewhere else when you make a call, pass disableSelection
$.ajax({
  type: "post",
  dataType: "json",
  url: "/api/login",
  // check out this method btw, it rules
  data: $('.element form').serialize(),
  disableSelection: $('.element button')
})
.done(function(data) {
  // ....
});

Both methods have their advantages, though I tend to prefer the doAjax method because it makes it obvious that there are options to this method that standard jQuery.ajax doesn't provide. If you do decide to use a prefilter, and the code will be edited/worked on by multiple people, I highly suggest adding an obvious namespace to the disableSelection property, call it something like myCompanyDisableSelection so that someone can search the code base for that string rather than try reading jQuery documentation to figure out what the hell disableSelection does :)

Sign up to request clarification or add additional context in comments.

Comments

1

Rather than extending the ajax functionality I would rather use the jQuery ajaxStart and ajaxComplete callbacks:

jQuery.fn.buttonDisable = function(v) {

    if(v)
        $(this).prop('disabled', true).addClass('animate-load').parents('html').addClass('busy');
    else
        $(this).prop('disabled', false).removeClass('animate-load').parents('html').removeClass('busy');

};

$( document ).ajaxStart(function() {
  $('.element button').buttonDisable(true);
});

$( document ).ajaxComplete(function() {
  $('.element button').buttonDisable(false);
});

By the way: .parents('html') is probably the most unperformant thing ever, use $('html') in the first place or at least .closest('html').

This method would globally run the function. Use beforeSend and complete in the ajax call if you want to controll it individually.

2 Comments

Is there a better method to toggle this usage? Because there may be times when I'm making an ajax call but there is no button, or perhaps I don't want to disable/enable a button.
as i said, within your ajax call use the beforeSend property to define a function
1

Try something like below:

    $.ajax({
        type: "post",
        dataType: "json",
        url: "/api/login",
        data: {
            username: username.val(),
            password: password.val(),
        },
        beforeSend: function () {
            $('.element button').prop('disabled', true).addClass('animate-load').parents('html').addClass('busy');
        },
        success: function () {
            $('.element button').prop('disabled', false).removeClass('animate-load').parents('html').removeClass('busy');
        },
    })

1 Comment

I don't want to keep repeating myself with the disable/enable on every ajax call. Would it be possible to append a setting through the array, like in my example code? and if it's set, run the beforeSend/success code?
-1

How about

$.ajaxSetup({
    beforeSend: function() {
      $('.element button').prop('disabled', true).addClass('animate-load').parents('html').addClass('busy');
    },
    complete: function() {
      $('.element button').prop('disabled', false).removeClass('animate-load').parents('html').removeClass('busy');
    }
});

2 Comments

you're missing a : function()
One problem with this method is if you ever pass one of those options to an actual $.ajax call it will override the behavior defined here. It would be better to use an $.ajaxPrefilter to add this functionality.

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.