Messaging Between Unrelated Lightning Web Components

Ben Butler
3 min readAug 6, 2021

--

Lightning Web Components can be used to send messages between unrelated components. Below is an example of two LWC responding to messages.

This is a Message Channel called PingPong. A medium which is used to receive and announce messages. This is how messages get passed between unrelated components.

<?xml version="1.0" encoding="UTF-8" ?>
<LightningMessageChannel xmlns="http://soap.sforce.com/2006/04/metadata">
<masterLabel>PingPong</masterLabel>
<isExposed>true</isExposed>
<description>This sends messages between two unrelated LWC</description>
<lightningMessageFields>
<fieldName>value</fieldName>
<description>The value to send to a system</description>
</lightningMessageFields>
<lightningMessageFields>
<fieldName>source</fieldName>
<description>The source of the system</description>
</lightningMessageFields>
</LightningMessageChannel>

The application in this article works like this:

  1. There is a Lighting application with two unrelated components, ping and pong.

2. When I enter text in the first LWC, ping, it appears as output on the second LWC, pong.

3. When I enter text in the second LWC, pong, it appears as output on the first LWC, ping.

The benefit of this is completely decoupled messaging-based LWC system. Imagine if all LWCs can be added to an app without any dependencies or hierarchies. Just messaging.

The source:

The system redundancies can be refactored but we can pretend that each system is intended for a specific context since this demonstrates the point of an object-oriented form of LWC design, where each LWC acts as a stand-alone unit. We can create complex systems micro-architecture-style systems, with easy-to-monitor logging, by scaling LWCs in this way.

This is the LWC named “ping”

HTML

<template>
<p>{value}!</p>
<lightning-input onchange={sendMessage} ></lightning-input>
</template>

Meta

<?xml version="1.0" encoding="UTF-8"?>
<LightningComponentBundle xmlns="http://soap.sforce.com/2006/04/metadata">
<apiVersion>52.0</apiVersion>
<isExposed>true</isExposed>
<targets>
<target>lightning__AppPage</target>
</targets>
</LightningComponentBundle>

JavaScript

import { LightningElement, wire } from 'lwc';
import { publish, subscribe, MessageContext } from 'lightning/messageService';
import PING_PONG_CHANNEL from '@salesforce/messageChannel/Ping_Pong__c';
export default class Ping extends LightningElement {
value = 'Pong Value...';
subscription = null;
@wire(MessageContext)
messageContext;
sendMessage(event) {
const payload = {
value: event.target.value,
source: 'ping'
};
publish(this.messageContext, PING_PONG_CHANNEL, payload);
}
subscribeToMessageChannel() {
this.subscription = subscribe(
this.messageContext,
PING_PONG_CHANNEL,
(message) => this.handleMessage(message)
);
}
handleMessage(message) {
if (message.source == 'pong'){
this.value = message.value;
}
}
connectedCallback() {
this.subscribeToMessageChannel();
}
}

This is the LWC named “pong”

HTML

<template>
<p>{value}!</p>
<lightning-input onchange={sendMessage} ></lightning-input>
</template>

Meta

<?xml version="1.0" encoding="UTF-8"?>
<LightningComponentBundle xmlns="http://soap.sforce.com/2006/04/metadata">
<apiVersion>52.0</apiVersion>
<isExposed>true</isExposed>
<targets>
<target>lightning__AppPage</target>
</targets>
</LightningComponentBundle>

JavaScript

import { LightningElement, wire } from 'lwc';
import { publish, subscribe, MessageContext } from 'lightning/messageService';
import PING_PONG_CHANNEL from '@salesforce/messageChannel/Ping_Pong__c';
export default class Pong extends LightningElement {
value = 'Ping Value...';
subscription = null;
@wire(MessageContext)
messageContext;
sendMessage(event) {
const payload = {
value: event.target.value,
source: 'pong'
};
publish(this.messageContext, PING_PONG_CHANNEL, payload);
}
subscribeToMessageChannel() {
this.subscription = subscribe(
this.messageContext,
PING_PONG_CHANNEL,
(message) => this.handleMessage(message)
);
}
handleMessage(message) {
if (message.source == 'ping'){
this.value = message.value;
}
}
connectedCallback() {
this.subscribeToMessageChannel();
}
}

--

--

No responses yet