Using jQuery's .on function how do I get the originating element for the event?

10,479

Solution 1

Hope this helps someone:

$('#container').on('click', '.remove-group', function(event) {
  $(this);          // returns $('.remove-group') equivalent
  $(event.target);  // returns $('.remove-group') equivalent

  $(event.delegateTarget);  // returns $('#container') equivalent
});

Reference: http://api.jquery.com/event.delegateTarget/

Edit from question author:

I just want to clarify some of the mistakes I originally made.

It would seem the .on() handler in jQuery has some specific usage that isn't clearly spelled out in the documentation.

  1. You can use .on() directly on the selector itself:

    $('button').on('click', function () { $(this).css('border', 'solid 1px red'); });
    

    It will work, but it will NOT apply to any future elements dynamically added to the page with the same selector. This is different from the way .live() used to work. You must bind to the document object to catch future elements as well as current ones. This is because the selector is now the element you are listening on and it will catch all click events that bubble up to that element (document being one of the topmost elements to listen on). Then you pass the selector for the element you're interested in as a second argument after the event name.

    $(document).on('click', 'button', function () { $(this).css('border', 'solid 1px red'); });
    

    Now the listener will filter out click events until it finds one that was originally fired on 'button' and bubbled up to document.

  2. You must supply a string selector, not a wrapped set. This will not work:

    var $buttons = $('button');
    $(document).on('click', $button, function () { $(this).css('border', 'solid 1px red'); });
    

For examples, see this jsbin.

Basically you just have to listen on a higher scope than the dynamic element. This makes sense considering that the dynamic elements you want to listen for are, by definition, being added/removed after your code runs and registers your event listener.

Solution 2

To get the "originating element for the event", you would use the target property of the event object:

$(document).on('click', '.remove-group', function (e) {
    $(e.target).closest('tr').remove();
});

However, that approach probably isn't what you actually want, since the originating element might actually be a descendant of .remove-group whose 'click' event simply bubbled up the targeted element - meaning you might remove the wrong row in the event of a nested table. In the context of the .on() handler, this does in fact refer to the element matched by .remove-group. To bind to a delegated event on this element using .on(), the syntax is as follows:

$(static-parent-element).on(event, selector-string, handler)

For example, this is the correct syntax:

$(document).on('click', '.remove-group', function () {
    $(this).closest('tr').remove();
});

This will match current and future .remove-group elements, and remove the nearest tr ancestor. You can (and should) replace document here with the closest parent element of .remove-group which exists in the DOM at the time of binding, and will still exist whenever this event is expected to be triggered (i.e. is static). Doing this minimizes the distance which the event has to bubble up the DOM tree before the event is triggered.

Solution 3

$(this) should work fine but try event.target in any case.

$(document).on('click', '.remove-group', function (event) {
    $(event.target).closest('tr').remove();
});

Demo: http://jsbin.com/inewoc/1/edit

Share:
10,479

Related videos on Youtube

Chev
Author by

Chev

I'm a passionate developer and I love to learn. I also love to share my knowledge with others. Both of those are the primary reasons why I'm here on Stack Overflow :)

Updated on July 11, 2022

Comments

  • Chev
    Chev almost 2 years

    I had code like this:

    $('.remove-group').click(function () {
        $(this).closest('tr').remove();
    });
    

    This worked fine until I needed to use delegated event handler to capture clicks for elements that will be added to the page in the future.

    $(document).on('click', '.remove-group', function () {
        $(this).closest('tr').remove();
    });
    

    This no longer works because the this keyword does not refer to the originating element.

    Any ideas?

    Update

    It would seem that in my efforts to simplify the code for my question I actually made it work. I was actually passing in a wrapped set that was assigned to a variable instead of the string selector.

    var $removeGroup = $('.remove-group');
    $(document).on('click', $removeGroup, function () {
        $(this).closest('tr').remove();
    });
    

    That doesn't seem to work when I do it that way.

    • nbrooks
      nbrooks over 11 years
      this should still refer to the .remove-group element though. What are you expecting it to refer to, and what do you think it is referring to? (might help to include some html)
  • jAndy
    jAndy over 11 years
    how should that do any help here? It might even cause more trouble if those elements are wrapped, then the event target will reference those instead.
  • nbrooks
    nbrooks over 11 years
    @jAndy You're right, of course - this was mainly a response to "how do I get the originating element for the event". As I had explained in my comment on the answer, this would still refer to the .remove-group element and for further help debugging we would need the HTML. Anyway, I have expanded my answer to (hopefully) be more useful in general.
  • Chev
    Chev over 10 years
    I like this answer. Simple and explanatory. I hope you don't mind that I amended it with a clarification of the mistakes I made.