0

I am trying to utilize .off() in my JS to handle turning off all clicking during an ajax request and then turning it back on once it is done. I know the code to use for that is ajaxStart().ajaxStop().

What I am running into is that my .on('click') uses a nameless function to work. I.e.: $(document).on('click', '-enter-delegated-elements-here-', function (e) { // Click stuff here, like the click to run the ajax request });

This creates a problem when for when, after I have turned off my event listeners with .off ($(document).off('click', '**');), I have to turn them back on. Unfortunately, plain $(document).on('click', '-enter-delegated-elements-here-'); does not work.

To demonstrate my point I have created this fiddle.

(a snippet is also here:)

$('add').on('click', '#add'); //here's the zinger!!!

var i = 0;
$('#add span').text(i);
$(document).on('click', '#add', function(e) {
  $('#catcher').append(i);
  i += 1;
  $('#add span').text(i);
});
$(document).on('click', '#stop', function(e) {
  if (!$(document).off('click', '#add')) {
    $(document).off('click', '#add');
    return;
  }
  $(this).text('Add five and re-enable catching');
  i += 5;
  $('#add span').text(i);
  $('add').on('click', '#add'); //here's the zinger!!!
});
<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js"></script>
<button id="add">
  Add to catcher: <span></span>
</button>
<button id="stop">
  Stop catching
</button>
<h2>Catcher:</h2>
<div id="catcher"></div>

(While there is no ajax request, the principle is still the same)

I am aware that I could create a function to handle this, i.e.:

function forClicks(e) {
  // Click stuff here, like the click to run the ajax request
}
$(document).on('click', '-enter-delegated-elements-here-', forClicks(e));

However, it becomes less practical to make a bunch of functions (like if you end up having multiple click handlers - to handle debouncers and whatnot, etc.) and also clutters up the global space when you could use nameless functions instead.

Does anyone know how I can turn back on an event handler which uses nameless functions, using .on() (after it has been turned off with .off())? Is there a way to do this or would it require another type of JS code (I am aware that .toggle() does not work anymore, but maybe something like it?).

Community
  • 1
  • 1
4lackof
  • 1,250
  • 14
  • 33
  • By nameless, you mean anonymous function? I am afraid that you have to explicitly specify it in a function and rebind it with `on` event after you detach it. Based on your sample, you can just disable the button if you want to avoid the event handlers getting fired when users click on the button. – choz Aug 29 '16 at 06:49
  • What is purpose of `$('add').on('click', '#add');`? – guest271314 Aug 29 '16 at 06:51

1 Answers1

2

There are at least three solutions to this:

  1. Disable the buttons during the ajax operations. This also has the useful effect of telling the user they're not available during that time.

  2. Use a flag to tell the handlers not to do anything, e.g.:

    var disableClicks = 0;
    

    then increment it when you start an ajax call, and decrement it when the call finishes (including if it fails).

    Then in the handlers:

    if (disableClicks) {
        return;
    }
    
  3. Use named functions, as you mentioned.

    I am aware that I could create a function to handle this, i.e.:

    However, it becomes less practical to make a bunch of functions (like if you end up having multiple click handlers - to handle debouncers and whatnot, etc.) and also clutters up the global space when you could use nameless functions instead.

    There's no need to make them globals. You just make them in scope for where you're using them. You can even wrap them up into a nice tidy controller object.

Example for #1 (disabling the button):

var i = 0;
$('#add span').text(i);
$(document).on('click', '#add', function(e) {
  $('#catcher').append(i);
  i += 1;
  $('#add span').text(i);
});
$(document).on('click', '#stop', function(e) {
  $("#add").prop("disabled", true);
  setTimeout(function() {
    $(this).text('Add five and re-enable catching');
    i += 5;
    $('#add span').text(i);
    $("#add").prop("disabled", false);
  }, 1000);
});
<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js"></script>
<button id="add">
  Add to catcher: <span></span>
</button>
<button id="stop">
  Stop catching
</button>
<h2>Catcher:</h2>
<div id="catcher"></div>

Example for #2 (a flag/counter):

var disableClicks = 0;
var i = 0;
$('#add span').text(i);
$(document).on('click', '#add', function(e) {
  if (disableClicks) {
    return;
  }
  $('#catcher').append(i);
  i += 1;
  $('#add span').text(i);
});
$(document).on('click', '#stop', function(e) {
  ++disableClicks;
  setTimeout(function() {
    $(this).text('Add five and re-enable catching');
    i += 5;
    $('#add span').text(i);
    --disableClicks;
  }, 1000);
});
<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js"></script>
<button id="add">
  Add to catcher: <span></span>
</button>
<button id="stop">
  Stop catching
</button>
<h2>Catcher:</h2>
<div id="catcher"></div>

Example for #3 (controller object):

var addController = {
  handler: function(e) {
    $('#catcher').append(i);
    i += 1;
    $('#add span').text(i);
  },
  enable: function() {
    $(document).on('click', '#add', addController.handler);
  },
  disable: function() {
    $(document).off('click', '#add', addController.handler);
  }
};
addController.enable();

var i = 0;
$('#add span').text(i);
$(document).on('click', '#stop', function(e) {
  addController.disable();
  setTimeout(function() {
    $(this).text('Add five and re-enable catching');
    i += 5;
    $('#add span').text(i);
    addController.enable();
  }, 1000);
});
<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js"></script>
<button id="add">
  Add to catcher: <span></span>
</button>
<button id="stop">
  Stop catching
</button>
<h2>Catcher:</h2>
<div id="catcher"></div>
T.J. Crowder
  • 1,031,962
  • 187
  • 1,923
  • 1,875
  • A flag/counter is definitely my preferred solution, even if I'm using named functions. Just seems a lot neater and easier to manage than a bunch of `.on()` and `.off()` calls. – nnnnnn Aug 29 '16 at 06:52
  • wow perfect! thank you for all the options, they all have their uses depending on the scenario. For my case, I will use the flag/counter. You got me thinking, and I turned it from a number to a boolean (although both work truthy/falsy) and got the if statement down to one line `if (disableClicks) return;` – 4lackof Aug 29 '16 at 19:53
  • @4lackof: You can use that exact line even if it's a counter. I always use counters because it's amazingly easy to have overlapping things. – T.J. Crowder Aug 30 '16 at 05:43