Reputation: 12680
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
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
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.
$('.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
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
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