Adam
Adam

Reputation: 12680

Click event not bubbling when image clicked

I have the following markup:

<ul>
    <li class="tgt"><img src="http://placehold.it/48x48" width="48px" height="48px"></li>
    <li class="tgt"><img src="http://placehold.it/48x48" width="48px" height="48px"></li>
    <li class="tgt"><img src="http://placehold.it/48x48" width="48px" height="48px"></li>
</ul>

Code from the fiddle:

$('.tgt').on('click', function (e) {
    if ($(e.target).hasClass('tgt')) {
        $(e.target).addClass('active');
    }
});

I attach a click handler using jquery's event delegation to all .tgt elements. For some reason, if I click on the image, the event does not bubble up to the li. Instead the event target is revealed to be the image.

Here's a fiddle: http://jsfiddle.net/CgC4V/

Why is the event not bubbling up to li.tgt?

Upvotes: 5

Views: 5201

Answers (4)

nnnnnn
nnnnnn

Reputation: 150080

The event is bubbling up, but the target element that you are testing with e.target is the element that was actually clicked as you can see here: http://jsfiddle.net/CgC4V/1/

That is the way that event bubbling is supposed to work - if the event didn't bubble your handler attached to the li elements would not be triggered.

You can use this to refer to the li that was clicked:

$('.tgt').on('click', function (e) {
    $('.active').removeClass('active');
    if ($(this).hasClass('tgt')) {
        $(this).addClass('active');
    }
});

You probably don't need to test whether the element has the tgt class though, because you already know it must be one of the li elements that originally had that class.

Demo: http://jsfiddle.net/CgC4V/3/

UPDATE for the comments:

"Should I then be accessing jquery.event.currentTarget instead? What about in cases where the context is not the jquery element. What property of jQuery.event has a reference to the correct element?"

Yes, event.currentTarget will give you the correct element. "Normally", and for the code you've shown, event.currentTarget would be the same as this, but if you were to do something to alter the value of this (e.g., if you've used $.proxy() or Function.prototype.bind()) then event.currentTarget will give you the right element.

Note also that sometimes event.currentTarget will be the same element as event.target (and this if you've not altered this) - in your example if you click the "dot" of the li element rather than the image then the target is the li itself.

Upvotes: 11

theftprevention
theftprevention

Reputation: 5213

You'll want to use $(this) instead of event.target, because $(this) will always be the <li> itself, where event.target will point to the image if the image is the deepest available element in the DOM that received a click event.

See this demo.

$('.tgt').on('click', function (e) {
    if ($(this).hasClass('tgt')) {
        $(this).addClass('active');
    }
});

Edit for clarification: Consider the results below.

When the <li> is clicked, and not the <img>:

  • $(this) points to the <li>
  • event.target points to the <li>

When the <img> is clicked:

  • $(this) points to the <li>
  • event.target points to the <img>

This is because, of all elements that receive a click event, event.target will always point to the one that is deepest in the DOM. $(this), however, will always sit on the <li> and will catch any events that bubble up from the clicked <img>.

Upvotes: 1

frabjousB
frabjousB

Reputation: 104

e refers to the event, but you want to add the class when the obj is clicked, so just change $(e.target) to $(this) and it should work:

$('.tgt').on('click', function (e) {
    if ($(this).hasClass('tgt')) {
        $(this).addClass('active');
    }
});

Upvotes: 1

DevlshOne
DevlshOne

Reputation: 8457

$('img').on('click', function (e) {
    if ($(e.target).parent('li').hasClass('tgt')) {
        $(e.target).parent('li').addClass('active');
    }
});

This will make the img the actual target but still provide the highlighting for the entire list item.

Upvotes: 1

Related Questions