An example to communicate between Lightning Web Components and Visualforce Pages

In the past, if you want to communicate between LWC, Aura and Visualforce page, you have to use postMessage() method. This is an article back in 2017:

https://developer.salesforce.com/blogs/developer-relations/2017/01/lightning-visualforce-communication.html

In the Winter ’20 release, we are introducing a new feature 'Lightning message service' to communicate across the DOM between Visualforce pages, Aura components.

Actually I have tried many examples, but it doesn't provide full example or it has some bugs due to missing scope.

Summarize steps:

  1. Create Message Channel
  2. Create LWC and Visualforce, then subscribe to that message channel.
  3. Publish a message (or send data).

1. Create Message Channel:

Here is an example of a message channel "SampleMessageChannel.messageChannel-meta.xml"

<?xml version="1.0" encoding="UTF-8"?>
<LightningMessageChannel xmlns="http://soap.sforce.com/2006/04/metadata">
    <masterLabel>SampleMessageChannel</masterLabel>
    <isExposed>true</isExposed>
    <description>This is a sample Lightning Message Channel.</description>
</LightningMessageChannel>

it will located under folder "force-app/main/default/messageChannels"

2. Create LWC and Visualforce, then subscribe to that message channel.

2.1 LWC

'LMS_lwc.html'

<template>
    <lightning-card title="LWC" icon-name="custom:custom18">
        <div class="slds-m-around_medium">
            <div style="margin-bottom:24px;"><h1>LWC - Message Service</h1></div>
            <div>Has subscribed: {subscribe}</div>
            <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>

LWC_LWC.js

import { LightningElement, track} from 'lwc';
import { APPLICATION_SCOPE, createMessageContext, MessageContext, publish, releaseMessageContext, subscribe, unsubscribe } from 'lightning/messageService';
import lmsDemoMC from "@salesforce/messageChannel/SampleMessageChannel__c";

export default class LMS_lwc extends LightningElement {
    @track _msg = '';
    @track receivedMessage = '';
    subscribe = false;
    channelName = lmsDemoMC;
    channel;
    context = createMessageContext();

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

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

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

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

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

2.2 Visualforce page

'LMS_Visualforce.page'

<apex:page lightningStylesheets="true">
    <header>
        <title>Visualforce -  Message Service</title>
    </header>
    
    <!-- Begin Default Content REMOVE THIS -->
    <h1>Visualforce -  Message Service</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.SampleMessageChannel__c}";
        var subscriptionToMC;

       function publishMessage() {
            //payload can be anything you want.
            const payload = {
                source: "Visualforce",
                messageBody: document.getElementById('vfMessage').value
            };
            sforce.one.publish(lmsDemoChannel, payload);
        }
        function subscribeMC() {
            if (!subscriptionToMC) {
                subscriptionToMC = sforce.one.subscribe(lmsDemoChannel, onMCPublished, {scope: "APPLICATION"});
            }
        }
        function unsubscribeMC() {
            if (subscriptionToMC) {
                sforce.one.unsubscribe(subscriptionToMC);
                subscriptionToMC = null;
            }
        }
        function onMCPublished(message) {
            console.log('VF on subscribeMC listening.... ');
            var textArea = document.querySelector("#txtMessages");
            textArea.innerHTML = message ? 'Message: ' + message.messageBody + '. <br/>Sent From: ' + message.source : 'no message payload';
        } 
    </script>
</apex:page>

Remember you need to click on subscribe first before you can receive any message from channel.

Happy coding!
Let us know if you have any question.

No Comments Yet.

Leave a comment