This question already has answers here:
What's the difference between event.stopPropagation and event.preventDefault?
(8 answers)
Closed 9 years ago.
I was answering a question here in SO, and I stumbled on an odd behavior.
Check this demo
It's working great. I'm adding event handlers and when I click the image I have
alert(2) without firing the link handler alert(1). The odd part is that, if I remove
the preventDefault, alert(1) still doesn't fire, but it follows the link.
How come that stopPropagation, prevents the handler from bubbling the event, but it needs preventDefault to not follow the link?
This is purely for an educational reason. I just want to understand what's happening.
//EDIT please see the demo before answering. I have handlers on two different elements.
Although stopPropagation prevents the handler of the parent element to fire, it doesn't prevent it from following the link. But doesn't stopPropagation, prevent it the event from bubbling? Doesn't it nullify the event for the parent element?
//Why the event is nullified for the handler alert(1) but not for the following of the link?
All events in Javascript fire on the outermost element interacted with and then fire again on every element in it's ancestry until it reaches the body. In this way the event is firing first on your img and then again on your a because your img is inside the a.
If this behavior is not desired, that is why you would use stopPropagation to prevent it from bubbling up the chain. In jQuery, it is easy to check what element originated the event, so you can ignore it in certain cases by using event.target.
if (e.target == this) {
// run code only when this element is the originator of the event
}
When a click event is fired there are basically two veins, the Javascript event, and the native event. If the native event isn't preventDefault() or return false somewhere, it is going to fire, regardless of any stopPropagation().
How come that stopPropagation, prevents the handler from bubbling the
event, but it needs preventDefault to not follow the link?
Well, you explained it well.
Default behaviour of a link is being followed. Preventing the default is stopping it from being followed.
Propagation behavior is event bubbling to the parent, preventing propagation stops the bubbling to the parent. This is different from following the link because following the link is something related to the link itself not attached to its parent, so, it's still there.
return false; if I remember correctly tells jQuery to do both.
Update:
I see you are differentiating the handlers from following the link, based on this, I think this is the answer for you:
jQuery stopPropagation not working when applied to textbox inside anchor
Related
MDN explains:
If an EventListener is added to an EventTarget while it is processing an event, that event does not trigger the listener. However, that same listener may be triggered during a later stage of event flow, such as the bubbling phase.
What are the ways to prevent this from happening?
Possible Solutions:
Call event.stopPropagation() when the event is invoked.
I'm not a fan of this solution because the solution is not localized near the problem. The solution is in where the click originates and the problem is the code that adds the new event listener.
Add the event listener inside of a setTimeout:setTimeout(() => {element.addEventListener('click', clickHandler},0)
This solution is cohesive: the problem of the new eventListener triggering immediately is solved right where the event listener is added. Also it doesn't stop propagation for an event that other listeners might depend on. However, it feels like a hack to wrap it inside a setTimeout like this.
Do better solutions exist to prevent the new event listener from firing immediately due to the click that caused the event listener to be added?
This problem occurred for me when attempting to make a popup appear that closes itself for a click outside. Since the click that creates the popup is also a click outside. The popup closes immediately.
Link to example use-case including solutions
Is it possible to prevent event triggering on bubbling and on capturing in JavaScript?
The e.stopPropagation() is not what I am looking for.
In my case I would like only a direct window blur to trigger the event. Triggering the blur event on window on every child control blur affects performance. (I believe that it is not related to the question, but still in order to avoid the xyz problem I will mention that I am using the blur event on window to check that the blur happened due to iframe click and in case it did, then I run some code. I.e. what I need here is a way to attach a blur listener to window, so that the blur listener would run only on window blur, but not on its children blur.)
Maybe there is a way to add an event listener to a target phase of window blur only? Or will the listener be always called on bubble and on capture and it is impossible to avoid?
event bubbling travels from child to parent. So it is essentially event capturing which you want to prevent.
When you add a event listener using
window.addEventListener("focus", callback, true/false)
This third argument suggest capturing or bubbling. So if you will just keeps it false event will just bubble and since window is the top most element it wont be propagated to anywhere else.
I have a couple of questions regarding events attached to DOM nodes. Consider the following:
http://jsfiddle.net/hXq6r/15/
Basic:
[1?] What level is the [I] (class="fixed") dom node? What level is the [II] class="container"> dom node?
[2?] How do you describe the relationship between the objects mentioned in 1? Ancestors are siblings?
[3?] When clicking the .fixed - why is the hyperlink event not triggered?
Problem:
All runs as expected. Now running this code in the Android WebView causes the problem: The click event is fired first on #button and then again on the hyperlink. I am running phonegap 1.4.1 I have no event handler attached to the hyperlink, it is just the default hyperlink event.
[4?] How is the default hyperlink event named? Click?
Advanced:
[5?] Which of the elements fires the click event first? Does it depend on the 1. level in the dom?
[6?] It seems that [I] fires first.
[7?] How can I stop the click event on [II] from firing if [I] fired previously? I just set a variable to check. Is this the best solution?
[8?] Event propagation - I assume this is of no use for this example, because we are looking at children, no ancestors. Should I delegate the event on a higher level?
Thanks : ). Hopefully this helps me with grasping the whole event basics.
Useful:
http://www.quirksmode.org/js/introevents.html
http://www.quirksmode.org/js/events_order.html
I have a page which has two different event listeners picking up click events from inside the page. One listener is generic to the site, the other is specific to the page. Recently, a link was added which runs through the first handler, which processes it, opens the url in a new window and then stops the event. The problem is, the second handler then executes, stops the event again and somehow the event continues and executes.
I have stopPropagation, and cancelBubble both executing on this event. When it arrives at the second handler, it has a prevented field which is set to true, but still it carries on. The only way to stop it is to put a check in the second handler which skips its code if the event arrives with prevented set to true.
My question is, why would this happen at all? Why is stopPropagation not working? This happens in all browsers, BTW.
I suppose you try to stop event from firing on the same element. Have you tried to use stopImmediatePropagation method?
As Samuel Liew correctly commented, adding return false; to the end of your first event handler might do the trick. This is because some browsers ignore the .stopPropagation() (However, others will ignore the return)
I have a DIV with a mouseout observer.
This DIV have also child Elements. mouseout event will alse be fired if the mouse pointer enter any of its child elements.
How can I prevent this behavior?
That’s expected behaviour.
However you can prevent it by giving those child elements an onmouseout event as well and returning false.
returning false in the event handler will stop the propagation of the event to parent-elements.
You may want to check a JS library.
JQuerys mouseleave function/event seems to be exactly what you’re looking for.
The API page also states the mouseleave event is IE-proprietary but JQuery emulates it for other browsers. If you don’t want to use JQuery you may want to check their source. api.jquery.com/mouseleave