Motivation behind this
Earlier I have written a post on Drag and Drop functionality using Salesforce Lightning Web Components leveraging pub-sub event propagation which works on publish-subscribe model.
With the introduction of Lightning Message Service (LMS) the communication between components can be possible either in single page or multiple pages over a message channel. It also works to communicate among Visualforce pages, Aura components, Lightning Web Components.
This flexible event communication mechanism drives me to do a proof-of-concept.
Lets get started.
Use Case
Business has a requirement to see a Company's location on google map when company is chosen.
Developer wants to build using Lightning Web Components where one component will list down the companies and other component will show the map. Both are unrelated but listen to the events based on subscription.
Possible End Results
After building the use case, it will perform the functionality as following video:
The screen will look like this:
Solution Approach
To start with, first create a message channel and push it to the org. the xml will be placed under force-app/main/default/messageChannels/ directory.
Here message channel name has given as Selected_EntityId and the file name will be Selected_EntityId.messageChannel-meta.xml
For more information, refer Create a Message Channel
<?xml version="1.0" encoding="UTF-8" ?> <LightningMessageChannel xmlns="http://soap.sforce.com/2006/04/metadata"> <masterLabel>SelectedEntityId</masterLabel> <isExposed>true</isExposed> <description>Message Channel to pass a entity Id</description> <lightningMessageFields> <fieldName>entityInfo</fieldName> <description>This is the record information that selected</description> </lightningMessageFields> </LightningMessageChannel>
Lets create publisher component, here it is showAccountList which will display accounts and clicking on the Account it will publish events.
showAccountList component:
HTML will like below, here onclick event has been used with div.
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 | <template> <lightning-card title="Lightning Message Service: communication between LWC Components" icon-name="custom:custom30"> <div class="c-container"> <lightning-layout> <lightning-layout-item padding="around-small"> <template if:true={accounts.data}> <template for:each={accounts.data} for:item="account"> <div class="column" key={account.Id} data-item={account.Id} onclick={handleClick}> <div class="slds-text-heading_small">{account.Name}</div> </div> </template> </template> </lightning-layout-item> </lightning-layout> </div> </lightning-card> </template> |
showAccountList.js
Few notable points in this js file:
- Importing message channel to communicate via LMS.
// Import message service features required for publishing and the message channel import { publish, MessageContext } from 'lightning/messageService'; import selectedEntity from '@salesforce/messageChannel/Selected_EntityId__c';
- Retrieving Account information from Controller importing getAccountLocations
- Publishing a message where entire account information is collected as an array and sending as payload in handleClick() event.
Entire js file as follows:
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 | /* eslint-disable no-console */ import { LightningElement, wire} from 'lwc'; import getAccountLocations from '@salesforce/apex/AccountHelper.getAccountLocations'; // Import message service features required for publishing and the message channel import { publish, MessageContext } from 'lightning/messageService'; import selectedEntity from '@salesforce/messageChannel/Selected_EntityId__c'; export default class ShowAccountList extends LightningElement { @wire(MessageContext) messageContext; //retrieve account records from database via Apex class @wire(getAccountLocations) accounts; //clicking the div fires this event handleClick(event) { //retrieve AccountId from div let accountId = event.target.dataset.item; let arr = this.accounts.data.find(element => element.Id == accountId); let payload = { record: arr }; publish(this.messageContext, selectedEntity, payload); } } |
AccountHelper.cls
getAccountLocations method it fetches Account data based on SOQL query. I want to show specific records for demo, that's why filter condition has been added.
Let's move to subscriber component which subscribes for the event and display account location in the map.
getAccountLocations method it fetches Account data based on SOQL query. I want to show specific records for demo, that's why filter condition has been added.
public with sharing class AccountHelper { @AuraEnabled (cacheable=true) public static List<Account> getAccountLocations(){ return[SELECT Id, Name, BillingStreet, BillingCity, BillingState, BillingPostalCode, BillingCountry FROM Account WHERE isDisplay__c = true]; } }
Screen will look like this:
displayLocationSubscriber component
It will be like this:
Code as follows where lightning-map is used to display location.
1 2 3 4 5 6 7 8 9 10 11 12 13 14 | <template> <lightning-card title="Lightning Map component will show selected Company Location" icon-name="custom:custom30"> <template if:true={isDisplayLocation}> <div class="slds-text-heading_small">{selectedAccountName}</div> <lightning-map map-markers={mapMarkers} markers-title={selectedAccountName} zoom-level = {zoomLevel} center = {center}> </lightning-map> </template> </lightning-card> </template> |
displayLocationSubscriber.js
Few important points:
- Defining the scope where subscriber component receives the message in our application. Here APPLICATION_SCOPE has been used.
- Scope feature is only available using @wire(MessageContext).
- There are methods to subscribe, unsubscribe and import message channel for using it.
- In the subscribe method, you can see arrow function has been used so it can call any methods of the class using this operator. Scope can be passed as parameter.
- handleMessage() method retrieves the account array and prepare attribute values to be used in lightning-map.
Entire js file as follows:
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 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 | import { LightningElement, wire, track} from 'lwc'; // Import message service features required for subscribing and the message channel import { subscribe, unsubscribe, APPLICATION_SCOPE, MessageContext } from 'lightning/messageService'; import selectedEntity from '@salesforce/messageChannel/Selected_EntityId__c'; let acct; export default class DisplayLocationSubscriber extends LightningElement { subscription = null; record; isDisplayLocation=false; @track mapMarkers = []; //holds account location related attributes markersTitle = ''; //title of markers used in lightning map. zoomLevel = 4; //initialize zoom level center; //location will be displayed in the center of the map selectedAccountName = ''; @wire(MessageContext) messageContext; // Standard lifecycle hooks used to subscribe and unsubsubscribe to the message channel connectedCallback() { this.subscribeToMessageChannel(); this.isDisplayLocation = false; } disconnectedCallback() { this.unsubscribeToMessageChannel(); } // Encapsulate logic for Lightning message service subscribe and unsubsubscribe subscribeToMessageChannel() { if (!this.subscription) { this.subscription = subscribe( this.messageContext, selectedEntity, (message) => this.handleMessage(message), { scope: APPLICATION_SCOPE } ); } } unsubscribeToMessageChannel() { unsubscribe(this.subscription); this.subscription = null; } // Handler for message received by component handleMessage(message) { //assigns account records acct = message.record; this.selectedAccountName = acct.Name; //prepares information for the lightning map attribute values. this.markersTitle = acct.Name; this.mapMarkers = [ { location: { Street: acct.BillingStreet, City: acct.BillingCity, State: acct.BillingState, Country: acct.BillingCountry, }, icon: 'custom:custom26', title: acct.Name, } ]; this.center = { location: { City: acct.BillingCity, }, }; this.zoomLevel = 6; this.isDisplayLocation = true; } } |
Create a Lightning App Builder page with two regions and place those components and display the page, selecting an account on left side component will display location on right side.
Finally we are done and thanks for reading.
No comments:
Post a Comment