Hi,
Given this controller called nestedctrl
import {Controller} from '@hotwired/stimulus';
export default class extends Controller {
static values = {
counter: {type: Number, default: 0},
childAmount: {type: Number, default: 0},
}
increment(event) {
const amount = 1;
this.counterValue = this.counterValue + amount;
this.dispatch('addedToCounter', {detail: {amount: amount}});
}
addChildAmount({detail: {amount}}) {
this.childAmountValue = this.childAmountValue + amount;
}
}
and this HTML
<div data-controller="nestedctrl"
data-nestedctrl-child-amount-value="5"
data-action="nestedctrl:addedToCounter->nestedctrl#addChildAmount"
>
<div data-controller="nestedctrl" data-nestedctrl-counter-value="2">
<button data-action="click->nestedctrl#increment">Bump up</button>
</div>
<div data-controller="nestedctrl" data-nestedctrl-counter-value="3">
<button data-action="click->nestedctrl#increment">Bump up</button>
</div>
</div>
It’s a multi level nested controllers, all the same. There can be more than 2 level of controllers, I keep 2 to stay readable.
On each button click, the counter-value of the closest controller is incremented.
An event is dispatched.
I want the event to be bubbled up to the upper level controller and handled by it in order to aggregate the counter value of each child.
But as they are the same “nestedctrl” controller, the event is not handled.
It seems that the problem lie in Scope::containsElement
containsElement = (element: Element): boolean => {
return element.closest(this.controllerSelector) === this.element
}
When this method is called, controllerSelector
is [data-controller=nestedctrl]
, and the closest element to the emitting element is itself, and not the parent one with the action.
The event cannot be bubbled up and handled by a parent which is the same controller as the dispatcher.
The same problem occurs when an event is dispatched by another controller inside a nested structure.
Is there any workaround or is it a bug