Years ago, when I taught Mathematics to both college and high school students, I used to show a fun puzzle that I found online called the Flash Mind Reader. It was a trick that had the students pick a number, then do a quick calculation. The Mind Reader would be able to guess the symbol next to their answer. Since then, Flash has fallen out of favor, so I thought I would recreate the trick in Salesforce.
Pick a 2 digit number, (example 23) then add the two digits together i.e. 2+3 = 5. Take your answer and subtract from the original number (23 – 5) and look up the symbol in the table. The Mind Reader will be able to tell you which symbol you picked when you click the Reveal button.
When working with Lightning Aura Components, if we wanted to communicate between two unrelated components, we used Application Events. With Lightning Web Components, the equivalent to Application events was the Publish Subscribe model, or PubSub for short. This had some drawbacks, as it required developers to download the pubsub class and deploy it to their org in order to communicate between two lightning web components that didn’t have a parent – child relationship. If the pubsub class changed, we would have to download a newer version of it.
The Lightning Message Service deprecates the need to use pubsub. With the Lightning Message Service, a Lightning Web Component can publish or subscribe to a Message Channel that the developer defines.
I was trying to think of an example of how I could use this, and I thought about sending a search string from one component, publishing that string over a message channel, and having another component subscribe to that channel and use that string to populate a datatable.
From the publisher component, we type in a search parameter. The string is sent over a message channel, and handled by the subscriber component, where it is used to query the database and return a list of Account records whose name match the search string.
We have to create a message channel before we can publish to it. In VSCode, in the force-app/main/default folder, create a folder called messageChannels. Then create a file with the name 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>
The publisher component allows the user to enter a search string. We can send this string to any other components that are subscribed to the message channel, Here we use a string to search by account name
The subscriber component subscribes to the SampleMessageChannel, and from that message channel, takes takes the string that was sent and queries the Salesforce database for matching Accounts
public with sharing class AccountSearch {
@AuraEnabled(cacheable=true)
public static List<Account> searchAccounts(String accountName){
String accountNameWildcard = '%' + accountName + '%';
List<Account> accountList = [SELECT Id, Name, Type FROM Account WHERE Name LIKE : accountNameWildcard];
return accountList;
}
}
With Lightning Web Components, we no longer have to click a button to perform filtering on tables. We can instead use a combination of event handlers and wire methods.
Here’s an example of a datatable that filters accounts according to the Industry picklist. Changing the value in the filter automatically refreshes the table to display the most relevant data.
import { LightningElement, track, wire} from 'lwc';
import { getPicklistValues } from 'lightning/uiObjectInfoApi';
import { getObjectInfo } from 'lightning/uiObjectInfoApi';
import ACCOUNT_OBJECT from '@salesforce/schema/Account';
import INDUSTRY_FIELD from '@salesforce/schema/Account.Industry';
import getAccountsByIndustry from '@salesforce/apex/PicklistFilterController.getAccountsByIndustry';
const columns = [
{ label: 'Name', fieldName: 'Name' },
{ label: 'Type', fieldName: 'Type' }
];
export default class PicklistFilter extends LightningElement {
@track value = '';
@track data = [];
@track columns = columns;
@wire(getObjectInfo, { objectApiName: ACCOUNT_OBJECT })
objectInfo;
@wire(getPicklistValues, { recordTypeId: '$objectInfo.data.defaultRecordTypeId', fieldApiName: INDUSTRY_FIELD})
IndustryPicklistValues;
handleChange(event) {
this.value = event.detail.value;
}
@wire(getAccountsByIndustry, { industry : '$value' })
accountsByIndustryCallback({error,data}){
this.data = data;
}
}
Apex Controller:
public with sharing class PicklistFilterController {
@AuraEnabled(cacheable=true)
public static List<Account> getAccountsByIndustry(String industry){
return [SELECT Id, Name, Type FROM Account WHERE Industry=:industry];
}
}
Calling a REST endpoint in LWC is similar to how it is handled in Visualforce or in Lightning Aura Components. We can make the callout within our Apex controller, then parse the result in our client side controller, then display the results back to the user within the lightning component.
Everyone knows about the magic eight ball toy, where you shake an eight ball shaped container, ask a question, and receive an answer. I chose the Magic Eight Ball API because there’s no authentication needed, which makes it a rather simple case to work with.
In order to make callouts to external APIs you will need to add the endpoint to your remote site settings in Salesforce.
The apex controller makes a callout to the endpoint and returns the response:
public with sharing class EightBallController {
@AuraEnabled
public static String askEightBall(String question){
HttpRequest req = new HttpRequest();
req.setEndpoint('https://8ball.delegator.com/magic/JSON/' + question);
req.setMethod('GET');
Http http = new Http();
HttpResponse res = http.send(req);
return res.getBody();
}
}
The Javascript controller handles the response from the rest endpoint, while the setBackgroundColor method sets the text color for the answer returned, based on whether the answer was a positive, neutral, or negative answer.
If I’m on an account and I want to quickly edit some of the information on my child records, I can create a button next to each record that will open a modal, which will allow me to edit the record and then return to my parent account record.
Apex Controller:
public with sharing class ContactsController {
@AuraEnabled(cacheable = true)
public static List<Contact> getContacts(id accountId){
return [SELECT Id, FirstName, LastName, Phone, Email FROM Contact WHERE accountId =:accountId];
}
}