6

I've attached delegated event handlers to a number of elements on the page using a single selector. As the events are triggered for individual elements, I'd like to turn off only that element's event handler based on some conditional logic. That means I won't necessarily want to disable the event on the very first click. But I can't figure out how to do it without turning off all of them.

HTML:

<button>One</button>
<button>Two</button>
<button>Three</button>

JS:

$(document).on('click', 'button', function(ev) {
    // doesn't work because argument needs to be a string
    $(document).off('click', $(ev.target));

    // doesn't do what I want b/c turns off events on all buttons, not just this one
    $(document).off('click', 'button');

    // doesn't work because event is on document, not button
    $(ev.target).off('click');
});

jQuery's off documentation says I need to provide a string as the second argument, not a jQuery object ($(ev.target)), but if I provide a string, there's no value that refers only to the item clicked.

From jQuery's off documentation:

To remove specific delegated event handlers, provide a selector argument. The selector string must exactly match the one passed to .on() when the event handler was attached. To remove all delegated events from an element without removing non-delegated events, use the special value "**".

So how do I turn off a delegated event handler for a specific element?

Here's a JSFiddle of the code above

UPDATE: Added a few examples of options that don't work, based on initial answers provided.

Matt
  • 23,363
  • 39
  • 111
  • 152
  • 1
    No, because that would remove *all delegated event handlers* from *all buttons*. I just want to remove it from the one being clicked. – Matt May 28 '15 at 16:42
  • 1
    As a workaround, this might be helpful: [Is there any way to delegate the event one in jQuery?](http://stackoverflow.com/questions/6873019/is-there-any-way-to-delegate-the-event-one-in-jquery) – showdev May 28 '15 at 16:43
  • Did you try `ev.target` as the 2nd arg? – lshettyl May 28 '15 at 16:44
  • @LShetty [Doesn't seem to work](http://jsfiddle.net/08ethzot/1/). – showdev May 28 '15 at 16:45

3 Answers3

10

After having read thru on the web, the answer is you can't! You can either remove all or none. A workaround could be something like the following.

$(document).on('click', '.btn', function (ev) {
    alert('pressed');
    $(this).removeClass("btn");
});

Demo@Fiddle

Sample HTML:

<button class="btn">One</button>
<button class="btn">Two</button>
<button class="btn">Three</button>
lshettyl
  • 8,166
  • 4
  • 25
  • 31
  • So this answer **will** work for me, but only because my circumstance is such that I only need the event to fire once. That said, I can see other cases where you'd need to remove a delegated event on a specific element based on some conditional logic that might not be true on the first fire of the event. For that reason, I'd like to see a way to do this. – Matt May 28 '15 at 17:11
  • 1
    In light of my comment above, it does make sense to me that a single event handler on the document itself is just that: a single event handler, even if it propagates to other elements. If you look at it that way, it doesn't seem logical to remove handlers from its child elements because they don't exist anyway. You'd either remove the whole thing, or nothing at all. – Matt May 28 '15 at 17:12
  • 3
    This answer seems to provide a lot of insight into this issue http://codereview.stackexchange.com/questions/16466/removing-jquery-event-handler-from-single-element-bound-by-delegate – Zack May 28 '15 at 17:17
1

In addition to what lshettyl said (the current top post) - an additional work around is to bind a new event listener directly to the element that you're trying to remove the listener and call stopPropagation() therein.

What this will do is prevent the event from traveling up the DOM and reaching the event handler that is initially bound to the document. Also this will allow you to keep some functionality on the button click, such as an alert to the user that this button has already been clicked - or something to that effect.

$(document).on('click', 'button', function(ev) {
    // Your logic to occur on button click

    // Prevent further click on just this button
    $(this).click(function(event) {
        event.stopPropagation();
    }):
});
kjb085
  • 11
  • 2
0

Question: Do you have to use the delegated events? LIke LShetty said, it is not possible to remove a delegated event for a single element. You either remove the entire event delegation, or leave it. You could try using a different selector instead like in this example

$('button').on('click', function(ev) {
    $('#output').append('Clicked! ');
    $(this).off('click');
});
<script src="https://ajax.googleapis.com/ajax/libs/jquery/1.7.2/jquery.min.js"></script>
<button>One</button>
<button>Two</button>
<button>Three</button>
<div id="output"></div>
Zack
  • 2,789
  • 33
  • 60
  • Yeah, it does need to be delegated, because these elements are going to be popping in and out of the page. It's a dynamic web app. – Matt May 28 '15 at 17:13
  • 1
    In that case, the best solution would probably be something like LShetty's solution where you add/remove a class on the elements once they are clicked, so the delegated event no longer applies to those elements. – Zack May 28 '15 at 17:21
  • Yeah, that really does seem like the best solution. – Matt May 28 '15 at 20:08