Both child and parent are clickable (child could be a link or div with jQuery click events). When I click on child, how do I only trigger parent click event but not the child event?
You dont need to trigger element click events when child elements are clicked, the click event bubbles up the dom tree if you dont stop propagation. Here you can see it working: jsfiddle just click on the blue span, the click event will bubble up to the ul :) Thanks for your answer.
If you just need to trigger a click event, you can omit the line that begins with for( . @Parag: Read it again. The loop is to click the same link 50 times, which is what it does.
Events have three phases:
<window>
and moving down through descendants towards the target of the event.Events also have a "default action", which happens after the bubbling phase. The default action is the browser-defined action that normally occurs for events of the specified type on the kind of element which is the target of the event (e.g. the browser navigating to the href
of an <a>
upon a click
, whereas a click
on another type of element will have a different default action).
The DOM Level 3 Events draft has a diagram that graphically shows how events propagate through the DOM:
Image Copyright © 2016 World Wide Web Consortium, (MIT, ERCIM, Keio, Beihang). http://www.w3.org/Consortium/Legal/2015/doc-license (Use permitted per the license)
For more information, on capture and bubbling, see: "What is event bubbling and capturing?"; The DOM Level 3 Events draft; or W3C DOM4: Events
For what you want, to get the event on the parent prior to, and prevent, the event on the child, you have to receive the event in the capture phase. Once you have received it in the capture phase, you have to stop the event from propagating to any event handlers on elements lower in the DOM tree, or which have registered to listen in the bubbling phase (i.e. all listeners on elements/phases which would be visited by the event after your listener). You do this by calling event.stopPropagation()
.
When adding the listener with addEventListener(type, listener[, useCapture])
, you can have the useCapture
argument be true
.
Quoting MDN:
[
useCapture
is] A Boolean that indicates that events of this type will be dispatched to the registered listener before being dispatched to any EventTarget beneath it in the DOM tree. Events that are bubbling upward through the tree will not trigger a listener designated to use capture. Event bubbling and capturing are two ways of propagating events that occur in an element that is nested within another element, when both elements have registered a handle for that event. The event propagation mode determines the order in which elements receive the event. See DOM Level 3 Events and JavaScript Event order for a detailed explanation. If not specified,useCapture
defaults to false.
event.preventDefault()
is used to prevent the default action (e.g. prevent the browser from navigating to the href
of an <a>
upon a click
). [This is used in the example below, but has no real effect as there is no default action for text. It's used here because most of the time when you are adding a click event handler you want to prevent the default action. Thus, it's a good idea to be in the habit of doing so, and just not doing so when you know you don't want to.]event.stopPropagation()
is used to prevent any handlers on elements later in any of the event phases from receiving the event. It does not prevent any additional handlers on the current element and phase from being called. It does not prevent the default action from occurring.event.stopImmediatePropagation()
: Handlers on the same element and phase are called in the order in which they are added. In addition to having the same effect as event.stopPropagation()
, event.stopImmediatePropagation()
prevents any additional handlers on the same element and event phase from receiving the event. It does not prevent the default action from occurring. Given that the requirement for this question is to prevent the event from propagating to children, we don't need to use this, but could do so instead of using event.stopPropagation()
. Note, however, that listeners on the same element are called in the order they are added. Thus, event.stopImmediatePropagation()
will not prevent the event from being received by those listeners on the same element and phase as your listener which were added prior to your listener.In the following example, event listeners are placed on both the parent and the child <div>
elements. Only the listener placed on the parent receives the event because it receives the event during the capture phase prior to the child and it executes event.stopPropagation()
.
var parent=document.getElementById('parent'); var child=document.getElementById('child'); var preventChild=document.getElementById('preventChild'); parent.addEventListener('click',function(event){ if(preventChild.checked) { event.stopPropagation(); } event.preventDefault(); var targetText; if(event.target === parent) { targetText='parent'; } if(event.target === child) { targetText='child'; } console.log('Click Detected in parent on ' + targetText); },true); child.addEventListener('click',function(event){ console.log('Click Detected in child (bubbling phase)'); }); child.addEventListener('click',function(event){ console.log('Click Detected in child (capture phase)'); },true);
<input id="preventChild" type="checkbox" checked>Prevent child from getting event</input> <div id="parent">Parent Text<br/> <div id="child" style="margin-left:10px;">Child Text<br/> </div> </div>
jQuery does not support using capture on events. For more information as to why see: "Why does jQuery event model does not support event Capture and just supports event bubbling"
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With