Understanding Event Propagation In LWC

Q.  Different LWC Events. if a's child is b and b's child is c. how to communicate from c to a ? event communication from one application to other?

Events in Lightning web components are built on DOM Events, a collection of APIs and objects available in every browser.

Lightning web components implement the EventTarget interface, which allows them to dispatch events, listen for events, and handle events.

 Create a Event In LWC
  •  Use CustomEvent Constructor
  •  Pass any parameter/arguments in detail property.
 Custom Event Name Should follow below rules

  • No uppercase letters
  • No spaces
  • Use underscores to separate words
     
Syntax for Event  Creation : 
const newCustomEventLWC = new CustomEvent('customeventname',  { detail :{
                                                                                                        name : "Event",                                                                                                                                Age: "xx"}
  });

Fire the Custom Event : 
    this.dispatchEvent(newCustomEventLWC)

Handle Event : 
2 ways 
   1. listen for an event: declaratively from the component’s HTML template
        
        parent.html
        <template>
            <c-child oncustomeventname={handleCustomEvent} </c-child>
        </template>

        parent.js
        import { LightningElement } from 'lwc';
        export default class Parent extends LightningElement {
            handleCustomEvent(){
                // Code runs when event is received
            }
        }

       NOTE : Listener in markup and handler in Js

    2. Attach an Event Programatically

        parent.js
        import {LightningElement} from 'lwc';
        export default class Parent extends LightningElement {
           constructor() {
             super();
             this.template.addEventListener('customeventname', this.handleCustomEvent);
           }

           handleCustomEvent = () => {};
        }
         NOTE : Listener and Handler both in JS 



2.1 To add an event listener to an element within the shadow boundary, use template.
this.template.addEventListener();

2.2 To add an event listener to an element that a template doesn’t own, call addEventListener directly.  MarkUp from slot

this.addEventListener()

Now the Answer to the above question stands in Knowing how this event propagation takes place
  • In LWC events propagate according to the same rules as DOM events. 
  • Uses only Bubble phase (Source - Parent - root),capture phase is not supported.
Define Event Propagation using Event.bubbles and Event.Composed

if Event.bubbles = True -  event propagates to source to root. default is False.
if Event.composed = True -  event can cross the Shadow DOM boundary.

Static Composition

<!-- grandparent.html -->
    <template>
        <h2>My app</h2>
        <c-parent onbuttonclick={handleButtonClick}></c-parent> 
                            <!-- listening to event onbuttonclick -->
    </template>

<!-- parent.html -->
    <template>
        <h3>I'm a parent component</h3>
        <div class='wrapper' onbuttonclick={handleButtonClick}>
                                                            <!-- div listening to event onbuttonclick -->

            <c-child onbuttonclick={handleButtonClick}></c-child>
                                      <!-- listening to event onbuttonclick -->

        </div>
</template>

<!-- child.html -->
    <template>
        <h3>I'm a child component</h3>
        <button onclick={handleClick}>click me</button>
    </template>

// child.js
    handleClick() {
        const buttonclicked = new CustomEvent('buttonclick', { 
            //event options 
        });
        this.dispatchEvent(buttonclicked);
    }

NOW There are 3 cases
 
Case 1  : Bubble = False and Composed = False (Default Case)
            The event bubbles up to <c-child> only meaning <div element line 3 below will not be able perform any action and only the component itself <c-child> line 6 below will hold in this case.

            <!-- parent.html -->
                1. <template>
                2. <h3>I'm a parent component</h3>
                3. <div class='wrapper' onbuttonclick={handleButtonClick}>
                   4.                                         <!-- div listening to event onbuttonclick -->
                   5.
                6. <c-child onbuttonclick={handleButtonClick}></c-child> = 
                                      <!-- listening to event onbuttonclick -->

                </div>
                </template>

Case 2 : Bubble = True and Composed = False 
Event bubbles up through the DOM, but doesn’t cross the shadow boundary. As a result, both c-child and div.wrapper can react to the event.

Case 3 : Bubble = True and Composed = True

Event bubbles up through the DOM, crosses the shadow boundary, and continues bubbling up through the DOM to the document root.   


Communication Across the DOM 


The above part shows how events can be used to make child to parent communication, what if we want to make communication with the components not linked to each other in any way.


Two ways


1. Lightning Message Service

2. Using Pub Sub Model


Lightning Message Service


3 steps Process

  • Create a Message Channel
  • Publish from Component
  • Subscribe from Component

<LightningMessageChannel xmlns="http://soap.sforce.com/2006/04/metadata">

    <masterLabel>CustomMessageChannel</masterLabel>

    <isExposed>true</isExposed>

    <description>Message Channel to pass a record Id</description>

    <LightningMessageFields>
        <fieldName>recordId</fieldName>
        <description>This is the record id that changed</description>
         //Can add multiple fields
    </LightningMessageFields>
</LightningMessageChannel>


//Pseudo code for publishing message channel
import {publish, MessageContext } from 'lightning/messageService'; import Custom_Message_Channel_Channel from '@salesforce/messageChannel/Custom_Message_Channel__c'; handleContactSelect(event){     const payload = {recordId:event.target.contact.Id}     publish(this.messageContext,Custom_Message_Channel_Channel, payload) } //Pseudo code for subscriber import {Subscribe, MessageContext } from 'lightning/messageService'; import Custom_Message_Channel_Channel from '@salesforce/messageChannel/Custom_Message_Channel__c'; subscription; recordId //will unscribe message channel during component destruction cycle @wire(MessageContext)messagecontext; //Encapsulate Logic for Subscribe subscribeToMessageChannel(){     this.subscription = subscribe(             this.messageContext,             Custom_Message_Channel_Channel,             (message) => this.handleMessage(message)             ); } handleMessage(message){ this.recordId =. message.recordId; } Pub Sub Model PUBSUB was required before spring 20 , with the introduction of LMS it is not required now , Although LMS is not supported in Communities So we may require Pub Sub there only.
 

Comments