Lightning Message Service: Quick Demo

In Winter 20 Release salesforce announce Lightning Message Service (LMS). We can use this single API to communicate between All Salesforce UI platform eg: Visualforce, Lightning Component, Lightning Web Components (LWC). Today I will share one demo where I will pass data between all type of components.
We will create each component and I will also explain the code as well. This is how our final output will look like:

Lightning Message Service (LMS) Demo, working sample

MessageChannel

For this first we need to create one MessageChannel to share data. We can use MetadataAPI to create and deploy this component. I am using VS code to create this in org.

  • Create a Folder “messageChannels” in “force-app\main\default”
  • Create a File with extension “demoMessage.messageChannel-meta.xml” I have used demoMessage you can use any name
  • Paste the below code
<?xml version="1.0" encoding="UTF-8"?>
<LightningMessageChannel xmlns="http://soap.sforce.com/2006/04/metadata">
    <masterLabel>demoMessage</masterLabel>
    <description>This is a sample Lightning Message Channel.</description>
    <isExposed>true</isExposed>
    <lightningMessageFields>
        <description>message</description>
        <fieldName>message</fieldName>
    </lightningMessageFields>
    <lightningMessageFields>
        <description>source</description>
        <fieldName>source</fieldName>
    </lightningMessageFields>
</LightningMessageChannel>

To get this component next time, update the package xml.

<?xml version="1.0" encoding="UTF-8" standalone="yes"?>
<Package xmlns="http://soap.sforce.com/2006/04/metadata">
    <types>
       <members>*</members>
       <name>LightningMessageChannel</name>
    </types>
    <version>47.0</version>
</Package>

Here I have created 2 fields one is message and second is source. You can create more fields based on your use case.

lms_LWC.html

<template>
    <lightning-card title="Lightning Message Service Demo" icon-name="utility:connected_apps">
        <div class="slds-m-around_medium">
            <p>MessageChannel: demoMessage__c</p>
            <br>
            <p>Subscribed: {subscribeStatus}</p>
            <br>
            <lightning-button label="Subscribe" onclick={subscribeMC}></lightning-button>
            <lightning-button label="Unsubscribe" onclick={unsubscribeMC}></lightning-button>
        </div>
        
        <div class="slds-p-around_medium lgc-bg">
            <lightning-input type="text" label="Mesage" value={myMessage} onchange={handleChange}></lightning-input>
            <lightning-button label="Publish" onclick={publishMC}></lightning-button>
        </div>

        <div class="slds-p-around_medium lgc-bg">
            <p>Received Message:</p>
            <lightning-textarea readonly value={receivedMessage} rows="7" style="height:150px;"></lightning-textarea>
        </div>

    </lightning-card>
</template>

lms_LWC.js

import { LightningElement, track, wire } from 'lwc';
import { publish, subscribe, unsubscribe, APPLICATION_SCOPE, MessageContext } from 'lightning/messageService';
import SAMPLEMC from "@salesforce/messageChannel/demoMessage__c";

export default class Lms_LWC extends LightningElement {
    @wire(MessageContext)
    messageContext;
    @track subscription = null;
    @track myMessage = '';
    @track receivedMessage = '';
     
    constructor() {
        super();
    }

    handleChange(event) {
        this.myMessage = event.target.value;
    }

    publishMC() {
        const message = {
            message: this.myMessage,
            source: "LWC"
        };
        publish(this.messageContext, SAMPLEMC, message);
    }
       
    subscribeMC() {

        if (this.subscription) {
            return;
        }
        this.subscription = subscribe(this.messageContext, SAMPLEMC, (message) => {
                this.handleMessage(message);
            },
            {scope: APPLICATION_SCOPE});
    }
   
    unsubscribeMC() {
        unsubscribe(this.subscription);
        this.subscription = null;
    }
 
    handleMessage(message) {
        this.receivedMessage = message ? JSON.stringify(message, null, '\t') : 'no message payload';
    }

    get subscribeStatus() {
        return this.subscription != null ? 'True' : 'False';
    }
}

Here we imports the message channel and the Lightning message service functions necessary for working with a Lightning message channel.
we use @wire(MessageContext) to create a Context object, which provides information about the Lightning web components that are using the Lightning message service. A component must be attached to the DOM before it can use the property decorated with @wire(MessageContext).

The subscribeMC() function first checks whether subscription is null. If not, it calls the Lightning Message Service’s subscribe() method and assigns it to subscription. The subscribe() method takes four parameters, the Context object, the name of the message channel, a listener method that handles the message, and scope. By setting the scope to APPLICATION_SCOPE, the subscribing component can receive messages on a message channel from anywhere in the application. When the listener method is invoked, It passes the message to the handleMessage() method. handleMessage() converts it from a JSON object into a string.
To clear any previous data, the unsubscribeMC() method calls the Lightning Message Service’s unsubscribe() method and sets the subscription variable to null.

LMS_LC.cmp

<aura:component implements="flexipage:availableForAllPageTypes" access="global" >
    <lightning:messageChannel type="demoMessage__c" aura:id="demoMessageChannel" onMessage="{!c.handleMessage}" scope="APPLICATION"/>
    <aura:attribute name="message" type="String"/>
    <aura:attribute name="sendMessage" type="String"/>

    <lightning:card>
        <aura:set attribute="title">
            <lightning:icon iconName="utility:connected_apps" size="small"/>
            Lightning Message Service Demo
        </aura:set>
        <div class="slds-m-around_medium">
            <p>MessageChannel: demoMessage__c</p>
            <br/>
            <p>Subscribed: True</p>
            <br/>
        </div>
        <p>Message:</p>
        <lightning:input value="{!v.sendMessage}" />
        <lightning:button class="slds-button slds-button_neutral" label="Publish" title="Publish"  onclick="{!c.publishMC}" />   
        
        <p>
            <p>Received Message:</p>
            <lightning:textarea name="input4" readonly="true" value="{!v.message}" class ="textarea"/>
        </p>
    </lightning:card>
</aura:component>

LMS_LCController.js

({
    publishMC: function(cmp, event, helper) {
        var message = {
            message: cmp.get("v.sendMessage"),
            source: "Lightning"
        };
        cmp.find("demoMessageChannel").publish(message);
    },

    handleMessage: function(cmp, message, helper) { 
        // Read the message argument to get the values in the message payload
        if (message != null && message.getParam("message") != null) {
            cmp.set("v.message", JSON.stringify(message.getParams(), null, '\t'));
        }
    }
})

Here, lightning:messageChannel component’s onMessage attribute is set to the expression “{!c.handleChanged}”, which registers the listener handleChanged. We use the publish() method to publish the data. We have used scope="Application" to define the application scope and can get the data from same browser tab.

LMS_VF.page

<apex:page lightningStylesheets="true">
    <apex:slds />
    <div>
        <h2>Lightning Message Service Demo</h2>
        <div class="slds-m-around_medium">
            <p>MessageChannel: demoMessage__c</p>
            <br/>
            <p>Subscribed: <label id="status" value="False" /></p>
            <br/><br/>
            <button onclick="subscribeMC()" class="slds-button slds-button_neutral">Subscribe</button>
            <button onclick="unsubscribeMC()" class="slds-button slds-button_neutral">Unsubscribe</button>
        </div>
        <p>Message:</p>
        <input type="text" id="theMessage" style="width: 100%"/>
        <br/>
        <button onclick="publishMC()" class="slds-button slds-button_neutral">Publish</button>
        <br/>
        <br/>
        <p>Received message:</p>
        <div lightning-textarea_textarea="" class="slds-form-element__control slds-grow textarea-container">
            <textarea id="messageTextArea" name="input4" readonly="true" class="slds-textarea" style="width: 100%; height: 150px;"></textarea>
        </div>
    </div>

    <script>
        // Load the Message Channel token in a variable
        var SAMPLEMC = "{!$MessageChannel.demoMessage__c}";
        var subscription;

        function publishMC() {
            const message = {
                message: document.getElementById('theMessage').value,
                source: "VisualForce"
            };
            sforce.one.publish(SAMPLEMC, message);
        }
 
        function handleMessage(message) {
            var textArea = document.querySelector("#messageTextArea");
            textArea.innerHTML = message ? JSON.stringify(message, null, '\t') : 'no message payload';
        }
 
        function subscribeMC() {
            if (!subscription) {
                document.getElementById('status').innerHTML = 'True';
                subscription = sforce.one.subscribe(SAMPLEMC, handleMessage, { scope: "APPLICATION" });
            }
        }
 
        function unsubscribeMC() {
            if (subscription) {
                document.getElementById('status').innerHTML = 'False';
                sforce.one.unsubscribe(subscription);
                subscription = null;
            }
        }
    </script>
    
</apex:page>

In Visualforce we are following same approach, We have created one variable to store the MessageChannel. We are calling subscribeMC() and unsubscribeMC() to subscribe the channel.

So we have created basic components for Lightning Message Service (LMS), We can use the same approach in our projects to pass data between components. We no longer need to setup Pub – Sub module to pass data between components.

Complete Code can be found here.

Did you like the post or do you have any questions, let me know in comments. Happy Programming 🙂

Advertisements

Leave a Reply

This site uses Akismet to reduce spam. Learn how your comment data is processed.