Event not bubbling to parent controller
See original GitHub issueIf I have two of the same controllers nested, the action does not bubble up to the parent controller.
<div data-controller="gallery" data-action="click->gallery#next">
<div data-controller="gallery">
<button>Click me!</button>
</div>
</div>
Here the gallery#next
action is not triggered even though the event bubbles up to this DOM element.
Here is a CodePen example.
There you can see that if the parent controller is different from the child controller it triggers the action correctly. I expect nesting the same controllers to behave the same way.
This is using Stimulus 2.0.0.
Issue Analytics
- State:
- Created 3 years ago
- Reactions:1
- Comments:5 (2 by maintainers)
Top Results From Across the Web
Event not Bubbling to Parent Element from Child Element
Your HTML is invalid. An <article> can't be a child of a <p> - check out the rendered HTML: console.log(document.body.innerHTML);
Read more >Event bubbling, capturing and how to prevent them
So when a event is emitted on the child it will bubble up to its parent. And it makes sense if you think...
Read more >How to Handle Click Events Not Bubbling Up to Document
The most obvious solution is to stopPropagation of the dropdown clicks to prevent the bubble-up. ... This fixes the unwanted expand/collapse of the...
Read more >Bubbling and capturing - The Modern JavaScript Tutorial
On a parent element (meaning an element which is not the target), listeners in the capturing phase will trigger before those for the...
Read more >Configure Event Propagation - Salesforce Developers
Events bubble up through the DOM; that's how children and parents communicate—props down, events up. When an event bubbles, it becomes part of...
Read more >
Top Related Medium Post
No results found
Top Related StackOverflow Question
No results found
Troubleshoot Live Code
Lightrun enables developers to add logs, metrics and snapshots to live code - no restarts or redeploys required.
Start Free
Top Related Reddit Thread
No results found
Top Related Hackernoon Post
No results found
Top Related Tweet
No results found
Top Related Dev.to Post
No results found
Top Related Hashnode Post
No results found
Thanks for the detailed response. Scoping for the most part works intuitively. I like that targets and actions only apply to the closest controller. My biggest issue is with this:
I think events should follow the normal JS bubble behavior. If we are listening to that event on a DOM element, that element becomes the
currentTarget
as the event bubbles up. At that point it feels like that event has escaped the inner scope. One can callevent.stopPropagation()
if they don’t want it to bubble up to a parent controller.Here’s an example of why I find it unintuitive:
The
gallery#next
is not triggered butalt-gallery#next
is triggered. The event basically jumps over the middle controller.Here’s my use case. I have a nested set of lists with a stimulus controller on each item to expand the nested list (think folders in a file system list view). I have another button on each item to expand the deepest part of the tree which is collapsed. The tricky part is I want to visually disable that button when there are no further descendants to expand. This means the parent button needs to update when a descendant expands/collapses.
I attempted to do this by emitting a custom event whenever expanding/collapsing the list. I expected the event to bubble up to each ancestor controller so I can update the button which manages the deep expansion. My work around is re-triggering the event on the parent element so it can escape the scope. The downside is we lose context of the target, but that can be passed through event
detail
if needed.This may be difficult to do since the nested lists can be arbitrarily deep. I could have a separate controller which wraps everything to manage updating the buttons, however I think this will be more complex than my current work around since the logic of what needs to be updated nicely follows the DOM tree and you’d lose that context.
I would be interested to hear counter examples where the current behavior is desirable and intuitive.
I’ve encountered this issue as well, and agree with @ryanb.
In my case, I’m using a “reveal” controller in a nested list. One use of this controller is to open a list item to reveal its children. Another use is during sorting, where I display modal for saving changes when sorting is changed.
So, I have the following:
When my sorting library triggers the
sort
event on the top-levelul
,show#reveal
is correctly called. But when thesort
event is triggered on theul
inside the nestedreveal
Stimulus controller, the top-levelshow#reveal
is not being called.The explanation @sstephenson provided does a great job at clarifying why
show#reveal
wasn’t called in this example. Are there cases where this behaviour is desired? It doesn’t feel right that a child controller takes over the parent controller just because they have the same name. If I remove the innerreveal
controllers, then it works, so the fact that there is asortable
controller nested doesn’t seem to trigger this issue (presumably because it’s a controller with a different name).