Pages

Showing posts with label Message Channel. Show all posts
Showing posts with label Message Channel. Show all posts

Friday, June 5, 2020

Let's Communicate !!! Lightning Message Service | Message Channel | Salesforce

Salesforce introduced a new feature Lightning Message Service (LMS) in Winter 20 and is generally available in Summer 20. This feature allows developers to easily communicate between VF and Lightning. This feature provides a quick channel to which consumers can consume and get both updates and convenient tags/modules, so developers don't have to worry about CometD resources and/or complicated Javascript.

In this blog, I will share with you how to create an LMS channel and then write code in LWC and VF both to send messages.

Use Case: I want to display selected account record details on the VF Page, I will select the account record on the LWC component and for that account, all information will be displayed on VF Page.

Before we start writing our code, we have to create a Message Channel. As of right now, the only way to leverage this is by using Metadata API.

How we can create Message Channel?

Message Channel can be created using VS Code. You need to follow the below steps to create Message Channel.

  1. Create a folder under force-app/menu/default folder and the folder name will be "messageChannels"
  2. Once you have created the folder, under that folder you need to create a file with naming convention as "SampleMessageChannel.messageChannel-meta.xml".
  3. Once you have created the file we need to add some XML code into that file and will look something like below

<?xml version="1.0" encoding="UTF-8"?>
<LightningMessageChannel xmlns="http://soap.sforce.com/2006/04/metadata">
   <masterLabel>PassRecordId</masterLabel>
   <isExposed>true</isExposed>
   <description>This Lightning Message Channel sends information from LWC to VF.</description>
   <lightningMessageFields>
       <fieldName>recordIdToSend</fieldName>
       <description>Record Id to be send</description>
   </lightningMessageFields>
   <lightningMessageFields>
       <fieldName>objectName</fieldName>
       <description>Identifies for which object we are sending the record id</description>
   </lightningMessageFields>
</LightningMessageChannel>

Where the "lightningMessageFields" tag is used to create a parameter that we need to send via LMS. We can create as many fields as we want per requirement. In my case, I have created "recordIdToSend" as a parameter which will hold Account record Id and "objectName" will hold the object name as 'Account'.
 
    4. Now, we need to add the entry for LMS in package.xml

<types>
        <members>*</members>
        <name>LightningMessageChannel</name>
    </types>


Let's create the LWC component and VF Page to publish and subscribe to the LMS.

VF Page code

To subscribe to the LMS on the VF page we use sforce.one API.
If you see in the below code I have subscribed the channel using sforce.one.subscribe method.

<!--
  @File Name          : LMS_AccountDetails.page
  @Description        : 
  @Author             : @tandonprateek
  @Group              : 
  @Last Modified By   : @tandonprateek
  @Last Modified On   : 6/6/2020, 7:52:36 AM
  @Modification Log   : 
  Ver       Date            Author      		    Modification
  1.0    6/6/2020   @tandonprateek     Initial Version
-->

<apex:page controller="LMS_AccountDetailsController">
    <script>
        var PASSRECORDID = "{!JSENCODE($MessageChannel.PassRecordId__c)}";
        var subscriptionToMC;
        if (!subscriptionToMC) {
            subscriptionToMC = sforce.one.subscribe(PASSRECORDID, onPublished, {scope: "APPLICATION"});
} function onPublished(message) { console.log('recordId on VF page ==== ' + message.recordIdToSend); getAccountData(message.recordIdToSend); } </script> <apex:form> <apex:actionFunction name="getAccountData" action="{!fetchAccountDetailRecord}" reRender="accountDetailsBlock"> <apex:param name="recordId" value=""></apex:param> </apex:actionFunction> <apex:pageBlock id="accountDetailsBlock" title="VF Page Display Account Details"> <apex:pageBlockSection id="accountSection"> <apex:outputField value="{!accDetailObject.Name}"></apex:outputField> <apex:outputField value="{!accDetailObject.Phone}"></apex:outputField> </apex:pageBlockSection> </apex:pageBlock> </apex:form> </apex:page>

Apex Class

/**
 * @File Name          : LMS_AccountDetailsController.cls
 * @Description        : 
 * @Author             : @tandonprateek
 * @Group              : 
 * @Last Modified By   : @tandonprateek
 * @Last Modified On   : 6/6/2020, 7:53:48 AM
 * @Modification Log   : 
 * Ver       Date            Author      		    Modification
 * 1.0    6/6/2020   @tandonprateek     Initial Version
**/

public with sharing class LMS_AccountDetailsController {

    public Account accDetailObject {get;set;}

    
    /**
    * @description 
    * @author @tandonprateek | 6/6/2020 
    * @return Pagereference 
    **/
    public Pagereference fetchAccountDetailRecord(){
        String accId = Apexpages.currentPage().getParameters().get('recordId');
        accDetailObject = [Select Id, Name, Phone from Account where Id =: accId];
        return null;
    }
}


LWC Component code

<!--
   @File Name          : accountInfoComponent.html
   @Description        : 
   @Author             : @tandonprateek
   @Group              : 
   @Last Modified By   : @tandonprateek
   @Last Modified On   : 6/6/2020, 7:51:35 AM
   @Modification Log   : 
   Ver       Date            Author      		    Modification
   1.0    6/6/2020   @tandonprateek     Initial Version
   -->
<template>
   <div class="slds-page-header">
      <div class="slds-grid">
         <div class="slds-col slds-has-flexi-truncate">
            <p class="slds-text-title_caps slds-line-height_reset">LWC Component Account Info</p>
            <h1 class="slds-page-header__title slds-m-right_small slds-align-middle slds-truncate"  title="AccountInfo">Acount Info</h1>
         </div>
      </div>
   </div>
   <lightning-button label="Get All Accounts" onclick={handleClick}></lightning-button>
   <lightning-card title="Account Result Data" icon-name="custom:custom3">
      <div class="slds-m-around_medium">
         <ul>
            <template for:each={finalData} for:item="acc">
               <li key={acc.Id} >
                  <a hrefv="javascript:void(0);" data-record-id={acc.Id} onclick={handleClickonAccountName}>{acc.Name}</a>
               </li>
            </template>
         </ul>
      </div>
   </lightning-card>
</template>


To use LMS in LWC we need to first import the methods from lightning/MessageChannel library and import the message channel, in my case, I need to add the below code to my LWC js file.

import { publish,createMessageContext,releaseMessageContext, subscribe, unsubscribe } from 'lightning/messageService';
import PassRecordId from "@salesforce/messageChannel/PassRecordId__c";

Below is my LWC js file

/**
 * @File Name          : accountInfoComponent.js
 * @Description        : 
 * @Author             : @tandonprateek
 * @Group              : 
 * @Last Modified By   : @tandonprateek
 * @Last Modified On   : 6/6/2020, 7:51:50 AM
 * @Modification Log   : 
 * Ver       Date            Author             Modification
 * 1.0    6/6/2020   @tandonprateek     Initial Version
**/
import { LightningElement, track } from "lwc";
import { searchAccountByName, searchAccountById, searchAccountsByIds, fetchAccounts, fetchAllAccounts } from "c/accountService";
import { publish,createMessageContext,releaseMessageContext, subscribe, unsubscribe } from 'lightning/messageService';
import PassRecordId from "@salesforce/messageChannel/PassRecordId__c";

export default class AccountInfoComponent extends LightningElement {
    searchKey = '';
    searchKeyText = '';
    data = [];
    context = createMessageContext();

    handleClick() {
        fetchAllAccounts()
            .then(result => {
                this.data = result;
                console.log(result);
            })
            .catch(error => {
                console.log(error.message);
            });
    }

    get finalData(){
        return this.data;
    }

    handleClickonAccountName(event){
        //let recordId = event.currentTarget.getAttribute('key');
        //let recordId = event.target.value;
        let recordId = event.target.dataset.recordId;
        console.log('recordId ==== ' + recordId);
        const payload = {
            recordIdToSend: recordId,
            objectName: 'Account'
        };

        publish(this.context, PassRecordId, payload);
    }

}

Here I have used Service Components to get the account records, you can refer to my previous blog about Service Component in LWC.
Now, to publish the LMS I need to call the publish method to call the LMS channel and pass the payload to the channel.

Below is the demo:



In summary, LMS provides us a very easy and quick way to move complex data across the DOM between LWC and VF Page, allowing for better interoperability.

References:

https://releasenotes.docs.salesforce.com/en-us/winter20/release-notes/rn_lc_message_channel.htm

https://newstechnologystuff.com/2020/03/22/lightning-message-service-quick-demo/