There might be a scenario where we have to conditionally propagate (allow/stop) events from crossing the shadow dom (when bubbling is true and composed is true)
This is how the typical syntax looks like when we want to propagate the event out of the shadow dom using composed is true.
this.template.querySelector('.pDiv')
.dispatchEvent(
new CustomEvent(
"senddata",
{bubbles: true, composed: true}
)
);
What if we want to conditionally control the event propagation out of shadow dom?
These are the sequence of steps in which they will get executed.
- User clicks on the button
- We are getting the div count that's wrapping lightning-button.
- we are bubbling the events and also composed is true, meaning, the events are capable of crossing the shadow boundary.
- In
child.htmlwe have event handlers on all thedivtags wrapping thelightning-buttonand Step3 is going to invoke the event listeneronsenddata. - The method
handleSendDatagets invoked. - For every iteration we are reducing the div count(fetched in Step2) by 1.
- When
this.allDivs === 1, it means it reached the top most div and we are stopping the event propagation.
Here is the code demonstrating the whole thing.
<template>
<!-- Though we have event listeners here they will
not be invoked since the event propagation
is stopped in step7. -->
<div onsenddata={handleSendData}>
<div onsenddata={handleSendData}>
<c-child onsenddata={handleSendData}></c-child>
</div>
</div>
</template>
import { LightningElement, track } from 'lwc';
export default class App extends LightningElement {
handleSendData(event){
// event.stopPropagation();
console.log('In parent component');
}
}
<template>
<!--Step4: We have event handlers on all the div tags wrapping the lightning-button
and this is going to invoke the event listener `onsenddata`.
-->
<div onsenddata={handleSendData} class="childDiv">
<div onsenddata={handleSendData} class="childDiv">
<div onsenddata={handleSendData} class="childDiv">
<div onsenddata={handleSendData} class="childDiv pDiv">
<!-- Step1: When user clicks on the button -->
<lightning-button label="click" onclick={handleClick}></lightning-button>
</div>
</div>
</div>
</div>
</template>
import { LightningElement, api } from 'lwc';
/**
* Show an item
*/
export default class Child extends LightningElement {
allDivs;
handleClick(event){
// Step2: We are getting the div count that's wrapping lightning-button
this.allDivs = this.template.querySelectorAll('.childDiv').length;
// Step3: we are bubbling the events and also composed is true;
// meaning, the events will cross the shadow boundary
this.template.querySelector('.pDiv')
.dispatchEvent(new CustomEvent("senddata", {bubbles: true, composed: true}));
}
// Step5: This method gets invoked
handleSendData(event){
console.log('In child component');
// Step7: When allDivs === 1, it means it reached the top most div
// and we are stopping the event propagation
if(this.allDivs === 1) {
event.stopPropagation();
}
// Step6: For every iteration we are reducing the count by 1.
this.allDivs -= 1;
}
}
Also, I have blogged everything I know about Events in LWC. Give it a look if you are curious.
Learn it by building it
Every course, every code repository, the discussion group and certificates of completion — one subscription.