LWC: How To Communicate Between Components Using PubSub Model(Multiple Parameters)


To communicate between components that aren’t in the same DOM tree we can use a singleton library that follows the publish-subscribe pattern.

This is similar to Application Events in Aura Components. When we need communicate to another components which don't have any relationship(Parent/Child) with other component in a same page we will use Pub - Sub pattern.

In a publish-subscribe pattern, one component publishes an event. Other components subscribe to receive and handle the event. Every component that subscribes to the event receives the event.

Below Example will show how to pass MultipleParameters from one component to another component.
First we need to create one LightningWebComponent  with name pubsub to copy pubsub.js file which is shared by Salesforce.This file mandatory to implement pub-sub model.
Copy below code into pubsub.js file and save it.
/**
* A basic pub-sub mechanism for sibling component communication
*
* TODO - adopt standard flexipage sibling communication mechanism when it's available.
*/
const events = {};
/**
* Confirm that two page references have the same attributes
* @param {object} pageRef1 - The first page reference
* @param {object} pageRef2 - The second page reference
*/
const samePageRef = (pageRef1, pageRef2) => {
const obj1 = pageRef1.attributes;
const obj2 = pageRef2.attributes;
return Object.keys(obj1)
.concat(Object.keys(obj2))
.every((key) => {
return obj1[key] === obj2[key];
});
};
/**
* Registers a callback for an event
* @param {string} eventName - Name of the event to listen for.
* @param {function} callback - Function to invoke when said event is fired.
* @param {object} thisArg - The value to be passed as the this parameter to the callback function is bound.
*/
const registerListener = (eventName, callback, thisArg) => {
// Checking that the listener has a pageRef property. We rely on that property for filtering purpose in fireEvent()
if (!thisArg.pageRef) {
throw new Error(
'pubsub listeners need a "@wire(CurrentPageReference) pageRef" property'
);
}
if (!events[eventName]) {
events[eventName] = [];
}
const duplicate = events[eventName].find((listener) => {
return listener.callback === callback && listener.thisArg === thisArg;
});
if (!duplicate) {
events[eventName].push({ callback, thisArg });
}
};
/**
* Unregisters a callback for an event
* @param {string} eventName - Name of the event to unregister from.
* @param {function} callback - Function to unregister.
* @param {object} thisArg - The value to be passed as the this parameter to the callback function is bound.
*/
const unregisterListener = (eventName, callback, thisArg) => {
if (events[eventName]) {
events[eventName] = events[eventName].filter(
(listener) =>
listener.callback !== callback || listener.thisArg !== thisArg
);
}
};
/**
* Unregisters all event listeners bound to an object.
* @param {object} thisArg - All the callbacks bound to this object will be removed.
*/
const unregisterAllListeners = (thisArg) => {
Object.keys(events).forEach((eventName) => {
events[eventName] = events[eventName].filter(
(listener) => listener.thisArg !== thisArg
);
});
};
/**
* Fires an event to listeners.
* @param {object} pageRef - Reference of the page that represents the event scope.
* @param {string} eventName - Name of the event to fire.
* @param {*} payload - Payload of the event to fire.
*/
const fireEvent = (pageRef, eventName, payload) => {
if (events[eventName]) {
const listeners = events[eventName];
listeners.forEach((listener) => {
if (samePageRef(pageRef, listener.thisArg.pageRef)) {
try {
listener.callback.call(listener.thisArg, payload);
} catch (error) {
// fail silently
}
}
});
}
};
export {
registerListener,
unregisterListener,
unregisterAllListeners,
fireEvent
};
view raw pubsub.js hosted with ❤ by GitHub
Now we will create two components publishComponent and subscriberComponent and pass data from publishComponent to subscriberComponent on click of button via pub-sub pattern.


When Call Subscriber button is clicked data will show in My Subscriber Component.Both Message and Source data will be listen from My Publisher Component.

Step1: Create publishComponent.html and save below code which contains CallSubscriber button.on click of it will the pass the predefined data to subscriberComponent.
publishComponent.html 
<template>
<lightning-card title="My Publisher Component">
<lightning-button label="Call Subscriber" variant="brand" onclick={callSubscriber}></lightning-button>
</lightning-card>
</template>

Step2:                                                                                                                                                     
  =>In publishComponent.js first we need to import the pubsub component to fireEvent using below   code.
                                  import { fireEvent } from 'c/pubsub';
 =>Next import the CurrentPageReference to pass the pafeRef to subscriberComponent using below code.
                                 import { CurrentPageReference } from 'lightning/navigation';
 => Add below wire api to get the current page reference.                                                                                                                              @wire(CurrentPageReferencepageRef;                             
 =>When button is clicked we need to fire event using below syntax.     
                   fireEvent(this.pageRef"typeYourEventName" , "parameter/data to pass");

In publishComponent.js save the below code which include all the above syntax to call the subscriberComponent.
publishComponent.js
/* eslint-disable no-console */
import { LightningElement,wire,track } from 'lwc';
import { CurrentPageReference } from 'lightning/navigation';
import { fireEvent } from 'c/pubsub';
export default class PublishComponent extends LightningElement {
//@track pubMessage = "SubscriberCalled";
@track pubMessage = { pubdata : "Message from Publisher",
source : "On Click of Button"}
@wire(CurrentPageReference) pageRef;
callSubscriber(){
console.log('callSubscriber');
fireEvent(this.pageRef, "pubsubEvent" , this.pubMessage);
}
}
Step3: In meta.xml file make isExposed as True and mention the interfaces where  you want  to show.
publishComponent.js-meta.xml
<?xml version="1.0" encoding="UTF-8"?>
<LightningComponentBundle xmlns="http://soap.sforce.com/2006/04/metadata">
<apiVersion>48.0</apiVersion>
<isExposed>true</isExposed>
<targets>
<target>lightning__AppPage</target>
<target>lightning__HomePage</target>
<target>lightning__RecordPage</target>
</targets>
</LightningComponentBundle>

Step4: Create subscribeComponent.html and use below to show the message from the publishComponent.
subscribeComponent.html
<template>
<lightning-card title="My Subscriber Component">
<h1>Message : {submessage}</h1>
<h1>Source : {msgSource}</h1>
</lightning-card>
</template>
Step5:

 =>In subscribeComponent.js  we need to import the pubsub component to register and unregister the event using below code.Add CurrentPageReference code also.
                   import { registerListener,unregisterAllListeners } from 'c/pubsub';
                   import { CurrentPageReference } from 'lightning/navigation';
 =>Add below wire api to get the current page reference.                                                                                          @wire(CurrentPageReferencepageRef;   
 =>In connectedCallback life cycle hook we need to register the event to get the data using below       code.
                   connectedCallback(){
                          registerListener("typeYourEventName","propertyToGetdata",this);
                      }
 =>In disconnectedCallback life cycle hook we need to deregister the event using below syntax.
                  disconnectedCallback(){
                         unregisterAllListeners(this);
                        }
In subscriberComponent.js save the below code which include all the above syntax.
subscriberComponent.js
/* eslint-disable no-console */
import { LightningElement,track,wire } from 'lwc';
import { CurrentPageReference } from 'lightning/navigation';
import { registerListener,unregisterAllListeners } from 'c/pubsub';
export default class SubscribeComponent extends LightningElement {
@track submessage;
@track msgSource;
@wire(CurrentPageReference) pageRef;
connectedCallback(){
registerListener("pubsubEvent",this.subscriberdata,this);
}
disconnectedCallback(){
unregisterAllListeners(this);
}
subscriberdata(evtMessage){
this.submessage = evtMessage.pubdata;
this.msgSource = evtMessage.source;
console.log('subEvent' + this.submessage);
}
}

Comments