As Moritz stated, you will need to fire the event on the child, as it is the most-inner element. That way the event bubbles up to each parent. The target
of the event will always be the child, but currentTarget
of the event will be the current element as it goes up the chain.
You must make sure that useCapture
is true
, for the ancestor elements you want the event to be picked-up for. See: EventTarget.addEventListener
.
useCapture
A Boolean
indicating 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
.
If you remove the useCapture
param (the second param) from parent.addEventListener
, only the grand-parent will get picked-up, following the child. It will not break the chain, unless you cancel the event in the child.
Note: If you are triggering a non-native event, it is preferred to use the CustomEvent
constructor. Again, you could just call the constructor directly if you wanted. This is just a browser-safe wrapper.
let grandParent = document.getElementById('x-grand-parent');
let parent = document.getElementById('x-parent');
let child = document.getElementById('x-child');
grandParent.addEventListener('custom-event', (e) => console.log(e.currentTarget.id), true);
parent.addEventListener('custom-event', (e) => console.log(e.currentTarget.id), true);
child.addEventListener('custom-event', (e) => console.log(e.currentTarget.id));
triggerCustomEvent(child, 'custom-event');
function triggerCustomEvent(el, eventName, options) {
let opts = Object.assign({
canBubble: true,
cancelable: true,
detail: {}
}, options);
let event = null;
if (window.CustomEvent && typeof window.CustomEvent === 'function') {
event = new CustomEvent(eventName, {
detail: opts.detail
});
} else {
event = document.createEvent('CustomEvent');
event.initCustomEvent(eventName, opts.canBubble, opts.cancelable, opts.detail);
}
el.dispatchEvent(event);
}
<div id="x-grand-parent">
<div id="x-parent">
<p id="x-child">
Hello World
</p>
</div>
</div>