Event Propagation in LWC

Updated: Jun 28

In previous blog, the event handler was declarative in parent component. There is one more way to handle a custom event.


Handle a Custom Event Programmatically - Use following statement to declare an event handler in constructor. where 'eventname' is the name of custom event, and 'handlerFunction' is the event handler method.


Declare Event Handler -

this.template.addEventListener('eventname', this.handlerFunction.bind(this));

Dispatch Event -

this.dispatchEvent(new CustomEvent('btnclick', { bubbles: true , composed : true }));

Above statement is dispatching a custom event. The second part of the statement is { bubbles: true , composed : true }, which is used for event propagation. While defining handler using programmatic statement, If we omit this statement the event would not cross the child component boundary, and event handler would not be called. When we create an event, bubbles and composed define the event propagation behavior.


bubbles - Define whether event bubble up the DOM or not.

composed – Define whether the event can pass through the shadow boundary or not.


Let's look how an event can be propagated in lightning web component.


1. When bubbles : false and composed : false (Default behavior) -

This is the default behavior, and bubbles and composed are not required to be defined explicitly. When this is in effect, the event would not bubble up the DOM, as well as it would not cross shadow boundary. We can listen these event only via defining the event handler to component that fires the event.

Example - Follow this example of previous blog, it shows the default behavior.

https://www.sfdcblogs.com/post/custom-events-in-lightning-web-components


2. When bubbles : true and composed : false -

In this behavior, the event bubbles up the DOM, but don't cross the shadow boundary. In simple terms, It bubbles up inside the current template, in which event is fired, but it would not cross it's boundary.

For example :- There are two component, where parent component contain child component. If event is fired inside child component, the event only bubbles up inside child component, and it would not cross it's boundary, and parent component will not be able to listen this event.

To bubble up event inside the template, dispatch the event to target element.


<!-- child.html  -->
<template>
    {childMsg}
    <div onbtnclick={handleBtnClick}>
    <lightning-button variant="brand" label="Submit" title="Brand action" onclick={handleClick} class="slds-m-left_x-small"></lightning-button>
    </div>
</template>

//child.js
import { LightningElement, track, api } from 'lwc';
export default class Child extends LightningElement {
    @track childMsg;
    handleClick(event){
this.template.querySelector('div')
.dispatchEvent(new CustomEvent('btnclick', { bubbles: true , composed : false }));
    }

    handleBtnClick (event)
    {
        this.childMsg = 'Event handled in Child template';
    }
}

Event fired by button will be handled by handler defined on <div> tag. This event can not be listened in parent component.




3. When bubbles : true and composed : true - This type of event can bubble up inside DOM, and can also cross the shadow boundary, and continue bubbling up to document root.


From Documentation -

IMPORTANT If an event uses this configuration, the event type becomes part of the component’s public API. It also forces the consuming component and all of its ancestors to include the event as part of their APIs.

Example -



<!-- app.html -->
    <template>
        <h1>{evtMessage}</h1>
        <c-child></c-child>
   </template>

There is no declarative handler in app.html

//app.js
import { LightningElement, track, api } from 'lwc';
export default class App extends LightningElement {
    @track evtMessage;
    constructor(){
        super();
        this.template.addEventListener('btnclick', this.handleClick.bind(this));
    }

    handleClick(event){
        this.evtMessage = 'Child component button click fired.';
    }
}


Event handler can be added in constructor, and the first statement should be super();

<!-- child.html -->
<template>
    <lightning-button variant="brand" label="Submit" title="Brand action" onclick={handleClick} class="slds-m-left_x-small"></lightning-button>
</template>


//child.js
import { LightningElement, track, api } from 'lwc';

export default class Child extends LightningElement {
    handleClick(event){
this.dispatchEvent(new CustomEvent('btnclick', { bubbles: true , composed : true }));
    }
}

bubbles : false and composed : true is not supported in LWC.


Please comment your questions.

©2019 by SFDC Blogs.