In my previous blog, we learned about how to Configuring Events and Propagation in LWC. While that blog primarily focuses on the communication behavior within the component markup hierarchy, this particular blog zeroes in on the disconnected architecture i.e. when the components are not in the markup hierarchy, how to do the handshaking.
The Lightning message service lets you define the scope of where subscribing components receive messages in your application. You can limit the scope to the active area of the application or set the scope to the entire application. Scope of LMS can be understood with the following flow.
LMS Scope |
To know more on Scope of Lightning Message Service, click here.
Let's consider an example to understand Lightning Message Service and when to use it. We have a main container component, housing couple of child components(Inner Components). So how to make the child components(Inner Components) listen to the behavior change in the parent component(Container Component in our case).
- Using Lightning Messaging Service : 👍 (Highly Recommended)
-
Using public method(@api decorated) in the Inner Component
: 👀(Look out for possibility)
Only applicable when we have parent-child relationship. If components are fully disconnected, this option is completely ruled out.
- Using pub-sub mechanism : 👎(Used where Lightning Messaging Service has limitation. To know more on LMS limitation, click here.
Disconnected Component Modal
|
NOTE: We can't simply use the Custom Event from main component 1 to make the other components listen to its behavior change. The reason behind this is the fact that the Custom Event programming modal works within the component hierarchy i.e. connected architecture and not outside the DOM or disconnected architecture.
Let's build up the solution to understand such communication behavior. Let's simplify our design with the following.
-
Create a
Lightning Message Channel: This is the first step to implement the lightning messaging
service. Create a folder first under force-app/main/default/messageChannels
as below:
notify.messageChannel-meta.xml :<?xml version="1.0" encoding="UTF-8"?> <LightningMessageChannel xmlns="http://soap.sforce.com/2006/04/metadata"> <masterLabel>NotifyMessageChannel</masterLabel> <isExposed>false</isExposed> <description>This is a sample Lightning Message Channel for Demo purpose.</description> <lightningMessageFields> <fieldName>textOne</fieldName> <description>This is to change the text of inner component one</description> </lightningMessageFields> <lightningMessageFields> <fieldName>textTwo</fieldName> <description>This is to change the text of inner component two</description> </lightningMessageFields> <lightningMessageFields> <fieldName>textContainerComponentTwo</fieldName> <description>This is to change the text of container component two</description> </lightningMessageFields> <lightningMessageFields> <fieldName>textClass</fieldName> <description>This is to set the text color in the inner component</description> </lightningMessageFields> </LightningMessageChannel>
-
Inner Component 1 :innerComponentOne.html :
<template> <span class={textClass}>{text}</span> </template>
innerComponentOne.js :import { LightningElement, api, wire } from 'lwc'; // Import message service features required for subscribing and the message channel import { subscribe, unsubscribe, MessageContext } from 'lightning/messageService'; import notify from '@salesforce/messageChannel/notify__c'; export default class InnerComponentOne extends LightningElement { @api text; @api textClass; @wire(MessageContext) messageContext; // Encapsulate logic for Lightning message service subscribe and unsubsubscribe subscribeToNotifyMessageChannel() { if (!this.subscription) { this.subscription = subscribe( this.messageContext, notify, (message) => this.handleNotifyMessage(message), ); } } unsubscribeToNotifyMessageChannel() { unsubscribe(this.subscription); this.subscription = null; console.log('Notify message unsubscribed in inner component one.'); } // Handler for message received by component handleNotifyMessage(message) { console.log('Notify message subscribed in inner component one with message.'); this.text = message.textOne; this.textClass = message.textClass; } // Standard lifecycle hooks used to subscribe and unsubsubscribe to the message channel connectedCallback() { this.subscribeToNotifyMessageChannel(); } disconnectedCallback() { this.unsubscribeToNotifyMessageChannel(); } }
-
Inner Component 2 :innerComponentTwo.html :
<template> <span class={textClass}>{text}</span> </template>
innerComponentTwo.js :import { LightningElement, api, wire } from 'lwc'; // Import message service features required for subscribing and the message channel import { subscribe, unsubscribe, MessageContext } from 'lightning/messageService'; import notify from '@salesforce/messageChannel/notify__c'; export default class InnerComponentTwo extends LightningElement { @api text; @api textClass; @wire(MessageContext) messageContext; // Encapsulate logic for Lightning message service subscribe and unsubsubscribe subscribeToNotifyMessageChannel() { if (!this.subscription) { this.subscription = subscribe( this.messageContext, notify, (message) => this.handleNotifyMessage(message), ); } } unsubscribeToNotifyMessageChannel() { unsubscribe(this.subscription); this.subscription = null; console.log('Notify message unsubscribed in inner component two.'); } // Handler for message received by component handleNotifyMessage(message) { console.log('Notify message subscribed in inner component two with message.'); this.text = message.textTwo; this.textClass = message.textClass; } // Standard lifecycle hooks used to subscribe and unsubsubscribe to the message channel connectedCallback() { this.subscribeToNotifyMessageChannel(); } disconnectedCallback() { this.unsubscribeToNotifyMessageChannel(); } }
-
Main Component 1: This component contains the above inner
components.
containerComponentOne.html
containerComponentOne.js<template> <lightning-card> <lightning-layout class="slds-var-m-around_medium"> <lightning-layout-item class="wide" style="width: 100%;"> <div class="slds-var-p-around_small"> <p>You're in container component one.</p> <lightning-button label="Hit Me On Container" variant="brand" onclick={handleClick}> </lightning-button> </div> <div class="slds-box"> <p>Inner Component One : <c-inner-component-one text={textOne} text-class={textClass}> </c-inner-component-one> </p> </div> <div class="slds-var-m-top_medium slds-box"> <p>Inner Component Two : <c-inner-component-two text={textTwo} text-class={textClass}> </c-inner-component-two> </p> </div> </lightning-layout-item> </lightning-layout> </lightning-card> </template>
containerComponentOne.js-meta.xmlimport { LightningElement, wire } from 'lwc'; // Import message service features required for publishing and the message channel import { publish, MessageContext } from 'lightning/messageService'; import notify from '@salesforce/messageChannel/notify__c'; export default class ContainerComponentOne extends LightningElement { textOne = 'Inner Component one didn\'t receive message from container component one'; textClass = 'slds-text-color_destructive'; textTwo = 'Inner Component two didn\'t receive message from container component one'; @wire(MessageContext) messageContext; connectedCallback() { console.log('Container component is called.'); } handleClick(event) { event.preventDefault(); const payload = { textOne: 'Inner Component One has received text from container component one via lms.', textTwo: 'Inner Component Two has received text from container component one via lms.', textContainerComponentTwo: 'Container Component Two has received text from container component one vis lms', textClass: 'slds-text-color_success' }; console.log('notify message channel published with the message to communicate across DOM'); publish(this.messageContext, notify, payload); } }
<?xml version="1.0" encoding="UTF-8"?> <LightningComponentBundle xmlns="http://soap.sforce.com/2006/04/metadata"> <apiVersion>51.0</apiVersion> <isExposed>true</isExposed> <targets> <target>lightning__HomePage</target> </targets> </LightningComponentBundle>
-
Main Component 2: This component has no relationship to
any of the above components and is stand alone component on the
home page which tries to listen to behavior change of
Main Component 1.
containerComponentTwo.html
containerComponentTwo.js<template> <lightning-card> <lightning-layout class="slds-var-m-around_medium"> <lightning-layout-item class="wide" style="width: 100%;"> <div class="slds-var-p-around_small"> <p>You're in container component Two.</p> <span class={textClass}>{text}</span> </div> </lightning-layout-item> </lightning-layout> </lightning-card> </template>
containerComponentTwo.js-meta.xmlimport { LightningElement, wire } from 'lwc'; // Import message service features required for subscribing and the message channel import { subscribe, unsubscribe, MessageContext } from 'lightning/messageService'; import notify from '@salesforce/messageChannel/notify__c'; export default class ContainerComponentTwo extends LightningElement { text = 'Container Component two didn\'t receive message from container component one'; textClass = 'slds-text-color_destructive'; @wire(MessageContext) messageContext; // Encapsulate logic for Lightning message service subscribe and unsubsubscribe subscribeToNotifyMessageChannel() { if (!this.subscription) { this.subscription = subscribe( this.messageContext, notify, (message) => this.handleNotifyMessage(message), ); } } unsubscribeToNotifyMessageChannel() { unsubscribe(this.subscription); this.subscription = null; console.log('Notify message unsubscribed in container component two.'); } // Handler for message received by component handleNotifyMessage(message) { console.log('Notify message subscribed in container component two with message.'); this.text = message.textContainerComponentTwo; this.textClass = message.textClass; } // Standard lifecycle hooks used to subscribe and unsubsubscribe to the message channel connectedCallback() { this.subscribeToNotifyMessageChannel(); } disconnectedCallback() { this.unsubscribeToNotifyMessageChannel(); } }
<?xml version="1.0" encoding="UTF-8"?> <LightningComponentBundle xmlns="http://soap.sforce.com/2006/04/metadata"> <apiVersion>51.0</apiVersion> <isExposed>true</isExposed> <targets> <target>lightning__HomePage</target> </targets> </LightningComponentBundle>
If you like this blog content and find inciteful, please comment and let me know.
Comments
Post a Comment