Data exchange between Aura, Lightning Web Components (LWC) and Visualforce

Using Lightning Message Services for event Communication between Lightning Web Components, Aura Components and Visualforce

Salesforce Lightning Message Service

Few months back, I wrote an article on how pub sub model can be used to communicate between Lightning Web Components. In that blog post, we used external library to pass event from child to Lightning Web Components.

Lightning Message Service

In Winter 20, Salesforce released Lightning Message Service which can be used to exchange data between Visualforce, Aura Component and Lightning Web Components. Unlike previous process, we don’t need to import any external library like pub or sub.

In this blog post, I would be creating Visualforce, Aura Component and Lightning Message Service and exchanging message between all of them using Lightning Message Service.

Lightning Message Channel

At the heart of Lightning Message Service, we have Lightning Message Channel. Its basically name of Schema which will hold actual message. For sake of this blog post, create file LMSDemoWin.messageChannel-meta.xml in folder messageChannels.

<?xml version="1.0" encoding="UTF-8"?>
<LightningMessageChannel xmlns="http://soap.sforce.com/2006/04/metadata">
   <masterLabel>LMS Demo</masterLabel>
   <isExposed>true</isExposed>
   <description>Winter 20 - LMS Demo.</description> 
</LightningMessageChannel>

Deploy Lightning Message Channel

Run below SFDX command to deploy this message channel on your Salesforce Org, run push command to deploy message channel on Scratch Orgs.

sfdx force:source:deploy -p "force-app/main/default/messageChannels/"

Once, Lightning Message Channel created, let’s start by creating our components and first we will create below Visualforce Page.

<apex:page>
    <!-- Begin Default Content REMOVE THIS -->
    <h1>Lightning Message Services - Demo - Winter 20</h1>
    <div>
        <p>Message To Send</p>
        <input type="text" id="vfMessage" />
        <button onclick="publishMessage()">Publish</button> 
        <br/> 
        <button onclick="subscribeMC()">Subscribe</button> 
        <button onclick="unsubscribeMC()">Unsubscribe</button> 
        <br/>
        <p>Messages Received:</p>
        <textarea id="txtMessages" rows="2" style=" width:100%;" />
    </div>
    <script> 
        // Load the MessageChannel token in a variable
        var lmsDemoChannel = "{!$MessageChannel.LMSDemoWin__c}";
        var subscriptionToMC;
       function publishMessage() {
            const payload = {
                source: "Visualforce",
                messageBody: document.getElementById('vfMessage').value
            };
            sforce.one.publish(lmsDemoChannel, payload);
        }
        function subscribeMC() {
            if (!subscriptionToMC) {
                subscriptionToMC = sforce.one.subscribe(lmsDemoChannel, onMCPublished);
            }
        }
        function unsubscribeMC() {
            if (subscriptionToMC) {
                sforce.one.unsubscribe(subscriptionToMC);
                subscriptionToMC = null;
            }
        }
        function onMCPublished(message) {
            var textArea = document.querySelector("#txtMessages");
            textArea.innerHTML = message ? 'Message: ' + message.messageBody + ' From: ' + message.source : 'no message payload';
        } 
    </script>
</apex:page>

In above code, we have few functions to subscribe , Unsubscribe and publish Lightning Message Channel. We can follow any schema for payload however that has to be followed by all clients as well. In our case, we are passing source and actual message body.

Next component we would build would be Aura Component

<aura:component description="testMessageAura" implements="flexipage:availableForAllPageTypes" access="global">
    <aura:attribute type="String" name="myMessage"/>
    <aura:attribute type="String" name="receivedMessage"/>
    <lightning:messageChannel type="LMSDemoWin__c" aura:id="lmsDemohannel" onMessage="{!c.handleReceiveMessage}"/>

    <lightning:card title="Aura Component" iconName="custom:custom18">
        <div class="slds-m-around_medium">
            <lightning:input type="text" value="{!v.myMessage}" label="Message To Send"/>
            <lightning:button label="Publish" onclick="{! c.handleClick}"/>
            <br/>
            <br/>
            <p>Latest Received Message</p>
            <lightning:formattedText value="{!v.receivedMessage}"/>
        </div>
    </lightning:card>
</aura:component>	

Controller of Aura Component

({
    handleClick: function(component, event, helper) {
        let myMessage = component.get("v.myMessage");
        const payload = {
            source: "Aura Component",
            messageBody: myMessage
        };
        component.find("lmsDemohannel").publish(payload);
    },
    handleReceiveMessage: function (component, event, helper) {
        if (event != null) {
            const message = event.getParam('messageBody');
            const source = event.getParam('source');

            component.set("v.receivedMessage", 'Message: ' + message + '. Sent From: ' + source);
        }
    }
});

As you can see in above Aura Component, we are not doing anything special to subscribe or unsubscribe Lightning Message Channel. Aura Component by default handles those operations once we declare them.

Last component we would be creating is Lightning Web Component

<template>
    <lightning-card title="LWC" icon-name="custom:custom18">
        <div class="slds-m-around_medium">
            <lightning-input label="Message To Send" type="text" value={_msg} onchange={handleChange}></lightning-input>
            <lightning-button label="Publish" onclick={handleClick}></lightning-button>
            <br>
            <lightning-button label="Subscribe" onclick={handleSubscribe}></lightning-button>
            <lightning-button label="Unsubscribe" onclick={handleUnsubscribe}></lightning-button>
            <p> Message Received</p>
            <lightning-formatted-text value={receivedMessage}></lightning-formatted-text>
        </div>
    </lightning-card>
</template>

Javascript of LWC

import { LightningElement, track} from 'lwc';
import { publish,createMessageContext,releaseMessageContext, subscribe, unsubscribe } from 'lightning/messageService';
import lmsDemoMC from "@salesforce/messageChannel/LMSDemoWin__c";
export default class LMS_MessageSenderReceiverLWC extends LightningElement {
    @track _msg = '';
    @track receivedMessage = '';
    channel;
    context = createMessageContext();

    constructor() {
        super();
    }
   
    handleSubscribe() {
        const parentPage = this;
        this.channel = subscribe(this.context, lmsDemoMC, function (event){
            if (event != null) {
                const message = event.messageBody;
                const source = event.source;
                parentPage.receivedMessage = 'Message: ' + message + '. Sent From: ' + source;
            }
        });
    }

    handleUnsubscribe() {
        unsubscribe(this.channel);
    }

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

    handleClick() {  
        const payload = {
            source: "Lightnign Web Component",
            messageBody: this._msg
        }; 
        publish(this.context, lmsDemoMC, payload);
    } 

    disconnectedCallback() {
        releaseMessageContext(this.context);
    }
}

Once we embed all three components (Visualforce, Aura and Lightning Web Components), we would be able to see Lightning Message Service in action as shown in below image :

Lightning Message Service in Salesforce

Related posts

Leave a Reply

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