Reputation: 704
I'm stuck on some event listeners. When one element is clicked I want to create another listener for clicks. For some reason they are both firing. Here's the code and a jsbin: http://jsbin.com/uHIyiGi/2/edit HTML
<div class="wrap">
<button>Click me</button>
</div>
JS
$('button').on('click', function(event){
$('body').append('<p>button clicked</p>');
$('.wrap').addClass('clicked');
$('body').on('click', '.clicked', function(e){
$('body').append('<p>.clicked clicked</p>');
$('.wrap').removeClass('clicked');
$('body').off('click', '.clicked');
});
});
From what I understand about event listeners, the second one should not fire until the '.clicked' element has a complete click event (a mouse down and mouse up), but it fires on the first click, meaning the event is fired even though the element doesn't have the trigger class until after the event. I'm seeing the event listener successfully removed each time, but it's called before I think it should be called. So, I'm really confused now... any suggestions? I'm hoping I have a face palm in my near future.
Upvotes: 2
Views: 1339
Reputation: 95022
Events bubble. When you click on the button, you're adding an event to the body. Once the event handler for the button is complete (meaning, the wrap now has a clicked class), it then continues to bubble up the DOM until it reaches the body. Since the body now has a new click event, said event also gets triggered. jQuery then looks within the body for an element matching the .clicked
selector, calling the handler on any that it finds. To stop this, you can either delay binding the event to the body with a setTimeout, or stop Propagation on the button's click event so that it won't bubble up to the body.
$('button').on('click', function(event){
event.stopPropagation();
...
Timeline:
clicked
class is added to .wrap
div.clicked
.clicked
selector.wrap
div that has a clicked
class and calls the event handler on that element.Upvotes: 5