Salesforce LWC: Lightning Message Service (Kind of Application Event in LWC)

Today in this blog we will learn about Lightning Message Service. We know about custom event in Lightning Web Component which we use when two LWC components are in same hierarchy.
But what if both Component are totally independent. So for that Salesforce has introduced Lightning Message Service in Winter'20. But it was a beta release.
Now in Salesforce Summer'20 release it is available and the main advantage of LMS (Lightning Message Service) is that we can use it in VF Pages or Aura Components or in LWC.

So when we want to use LMS then we are going to send message from one component to another. It means there will be one Publisher (who is publishing the message) and other will be Subscriber (who is receiving the message).

Now if Publisher and Subscriber want to communicate then both want some channel from which they can pass their communication. So for that we need Lightning Message Channel. 

Lightning Message Channel: Lightning Message Channel is a new Metadata and only available from v47.0
Name of Lightning Message Channel will be messageChannelName.messageChannel-meta.xml
Now the content of this file will be following:

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
<?xml version="1.0" encoding="UTF-8"?>
<LightningMessageChannel xmlns="http://soap.sforce.com/2006/04/metadata">
    <description>This Lightning Message Channel sends information.</description>
    <isExposed>true</isExposed>
    <lightningMessageFields>
        <description>message To Send</description>
        <fieldName>messageToSend</fieldName>
    </lightningMessageFields>
    <lightningMessageFields>
        <description>My source?</description>
        <fieldName>sourceSystem</fieldName>
    </lightningMessageFields>
    <masterLabel>MyMessageChannel</masterLabel>
</LightningMessageChannel>

If you see the above highlighted text that is the Messaging Channel Name which we will use in our Publisher and Subscriber Component.

Use Case: Let us take one scenario to better understand the concept of LMS. Suppose we have two separate LWC Component.

Component 1 : User Interface for searching a Contact Record. [Publisher]
Component 2: User Interface to show the search result. [Subscriber]

Publisher Component:
Below is the basic UI of Publisher Component:

1
2
3
4
5
6
7
8
9
<template>
    <lightning-card title="Contact Search Box" icon-name="custom:custom14">
        <div class="slds-m-around_medium">
            <p>Search Contact</p>
            <br>
            <lightning-input type="text" placeholder="Enter some text" onchange={handleChange}></lightning-input>
        </div>
    </lightning-card>
</template>

In above UI we have just one input box where user will enter some string to search Contact.

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
import { LightningElement, wire } from 'lwc';
import {MessageContext, releaseMessageContext, publish} from 'lightning/messageService';
import messageChannel from '@salesforce/messageChannel/MyMessageChannel__c';
import getContactList from '@salesforce/apex/PublisherSearchResultHandler.findContact';

export default class PublisherComponent extends LightningElement {
    @wire(MessageContext) messageContext;

    handleChange(event) {
        const searchValue = event.target.value;
        if(searchValue.length >= 2){
            getContactList({searchString : searchValue}).then(result => {
                publish(this.messageContext, messageChannel, result);
            }).catch(error => {
                window.alert(error);
            })
        }
    }
     
    disconnectedCallback() {
        releaseMessageContext(this.context);
    }
}

Now in above Java Script if you see, we have imported two libraries apart from LightningElement and Apex Class.
First one is from lightning/messageservice which will help Java Script to publish the message and second one is the Message Channel which will identify the correct channel and destination of message.
So once user will type some string then we are calling apex Class to get list of Contact. Below is the Apex Class:

1
2
3
4
5
6
7
public with sharing class PublisherSearchResultHandler {
    @AuraEnabled
    public static List<Contact> findContact(String searchString){
        String query = 'Select Id, FirstName, LastName, Email from Contact where Name LIKE \'%' + searchString + '%\'';
        return Database.query(query);
    }
}

Once we will receive result then we are using publish (highlighted in Java Script) method to send message to Subscriber.

Subscriber Component:
Below is the basic Lightning Data Table which will display the message (list of contacts):

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
<template>
    <lightning-card title="Contact Search Results" icon-name="standard:avatar">
        <div class="slds-m-around_medium">
            <br/>
            <lightning-datatable key-field="Id" data={contactData} columns={columns}></lightning-datatable>
        </div>
        <div slot="footer">
            <lightning-button label="Clear" variant="brand" onclick={clearData} disabled={isDisable}></lightning-button>
        </div>
    </lightning-card>
</template>

Below is the Java Script which is also using same libraries which Publisher Component is using:

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
import { LightningElement, track, wire} from 'lwc';
import {MessageContext, subscribe, unsubscribe, APPLICATION_SCOPE} from 'lightning/messageService';
import messageChannel from '@salesforce/messageChannel/MyMessageChannel__c';

export default class SubscriberComponent extends LightningElement {
    @wire(MessageContext) messageContext;
    @track subscription = null;
    @track contactData = [];
    @track columns = [
        { label: 'First Name', fieldName: 'firstName' },
        { label: 'Last Name', fieldName: 'lastName'},
        { label: 'Contact Email', fieldName: 'email', type: 'email' }
    ];
    @track isDisable = true;

    connectedCallback() {
        if (this.subscription) {
            return;
        }
        this.subscription = subscribe(
            this.messageContext,
            messageChannel, (message) => {
                this.handleMessage(message);
            },
            {scope: APPLICATION_SCOPE}
        );
    }

    handleMessage(message) {
        let editableMessage = JSON.parse(JSON.stringify(message));
        let contactData = [];
        for(let i = 0; i <= editableMessage.length; i++){
            if(editableMessage[i] !== undefined){
                let row = editableMessage[i];
                row.Id = editableMessage[i].Id;
                row.firstName = editableMessage[i].FirstName;
                row.lastName = editableMessage[i].LastName;
                row.email = editableMessage[i].Email;
                contactData.push(row);
            }
        }
        if(contactData.length > 0){
            this.isDisable = false;
        }
        this.contactData = contactData;
    }

    clearData(event){
        this.contactData = [];
        this.isDisable = true;
    }
}

In above java Script we have used connectedCallBack function so that as soon this component load it get subscribed to the message channel. In this method we have used subscribe method to subscribe it for receiving the messages from Publisher component. This subscribe method will decide once message will be received then which method will execute.

Limitations:
LMS does not support following experience:
  1. Salesforce Mobile App
  2. Lightning Out
  3. Lightning Community
Example:


References:
  1. https://developer.salesforce.com/docs/component-library
  2. https://releasenotes.docs.salesforce.com/en-us/summer20/release-notes


Some other very useful blogs to learn more about Salesforce:

  1. https://www.sfprompt.com/
  2. https://manish-porwal.blogspot.com/

Comments

Followers

Popular posts from this blog

Salesforce LWC: Multi-Record Creation using Lightning Web Component

Salesforce LWC: Basic Drag and Drop Functionality

Salesforce Lightning Web Component: Dynamic Column Selection in Lightning Datatable