I have a parent <div>
with one child <div>
in memory - not attached to the current document. I want to trigger a CustomEvent
on the child but listen to that event from the parent. Here is my code:
var parent = document.createElement('div');
var child = document.createElement('div');
parent.appendChild(child);
parent.addEventListener('boom', function(event) {
console.log('parent listener', event); // <~ This never runs!
});
var event = new CustomEvent('boom', { bubbles: true });
child.dispatchEvent(event);
This code doesn't work as expected. The event listener on the parent never fires. This seems to be a contradiction of the JavaScript event system whereby events bubble up from the target. However, if I modify the final two lines of this snippet to the following, the callback fires as I would expect it to:
document.body.appendChild(parent);
child.dispatchEvent(event);
In other words, if I append my fragment as a subtree of the document before dispatching the event, then the parent event listener fires exactly as expected. Why? Is there a way to allow bubbling when using detached DOM elements?
stopPropagation()Returns: undefined. Description: Prevents the event from bubbling up the DOM tree, preventing any parent handlers from being notified of the event.
Event bubbling is a way of event propagation in the HTML DOM. It relates to the order in which events are propagated in nested elements. In bubbling, when an event happens, the handler of the innermost element runs, then the parents, and then the further ancestor elements.
Detached DOM elements are the elements which have been removed from the DOM but their memory is still retained because of JavaScript. This means that as long the element have a reference to any variable or an object anywhere, it does not garbage collected even after destroyed from the DOM.
Why [doesn't bubbling work on detached elements]?
To answer your first question, I looked at the W3C "UI Events (formerly DOM Level 3 Events)" spec, and didn't see anything that addressed this issue specifically. However, the event phase portion mentions a few things that makes this behavior seem reasonable.
As the next step, the event object must complete one or more event phases. This specification defines three event phases: capture phase, target phase and bubble phase. Event objects complete these phases in the specified order using the partial propagation paths as defined below. A phase must be skipped if it is not supported, or if the event object's propagation has been stopped. For example, if the Event.bubbles attribute is set to false, the bubble phase will be skipped, and if Event.stopPropagation() has been called prior to the dispatch, all phases must be skipped.
Emphasis mine.
The spec then goes on to list the phases:
- The capture phase: The event object must propagate through the target's ancestors from the Window to the target's parent. This phase is also known as the capturing phase. Event listeners registered for this phase must handle the event before it reaches its target.
- The target phase: The event object must arrive at the event object's event target. This phase is also known as the at-target phase. Event listeners registered for this phase must handle the event once it has reached its target. If the event type indicates that the event must not bubble, the event object must halt after completion of this phase.
- The bubble phase: The event object propagates through the target's ancestors in reverse order, starting with the target's parent and ending with the Window. This phase is also known as the bubbling phase. Event listeners registered for this phase must handle the event after it has reached its target.
Again, emphasis mine. The spec never calls out what happens with detached elements explicitly. Given that the target and bubble phases require the path to go from the element to the window, and that no path is possible on detached elements, it follows that the target and bubble event phases must be skipped because those paths are not supported.
Is there a way to allow bubbling when using detached DOM elements?
As far as I can tell, there's nothing built-in that would allow bubbling. You might be able to fake bubbling with some custom code, but that would require checking whether the element is detached every time you trigger an event.
Another thought would be to add the elements to the DOM, trigger the event, and detach the elements. As I haven't tested this, I have no idea whether it would work.
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