Saturday, 28 March 2020

Display Real Time Notifications on Lightning Aura Component using Platform Events

Hi,

Here we are going to learn how can we subscribe to platform event and listen to platform events.

You can go through my YouTube channel "Salesforce Techbook" for practical session on the same.
The following has practical session from "Salesforce Techbook"
https://www.youtube.com/watch?v=i5XSf_uF9XI


We have to include "lightning:empApi " component in Lightning Component and use methods "subscribe" ,"unsubscribe" methods to subscribe to platform events or unsubscribe to platform event.
<lightning:empApi aura:id="empApi"/>
lightning:empApi :

provides access to methods for subscribing to a streaming channel and listening to event messages. All streaming channels are supported, including channels for platform events, PushTopic events, generic events, and Change Data Capture events. The lightning:empApi component uses a shared CometD connection.

Here Account_Creation_Event__e is Platform Event Name

AccountNotifications.cmp

<aura:component implements="force:appHostable" >
<lightning:empApi aura:id="empApi" />
     <aura:handler name="init" value="{!this}" action="{!c.subscribe}"/>
     <aura:attribute name="notifications" type="List"/>
     <aura:attribute name="evntRecieved" type="boolean"/>
    <lightning:card title="Account Notifications">
        <aura:if isTrue="{!v.evntRecieved}"> 
             <p class="slds-p-horizontal_small">
                <ui:message severity="info" closable="true">
                     <aura:iteration items="{!v.notifications}" var="val">
                        <p>{!val}</p>
                    </aura:iteration>
                 </ui:message>
            </p>
        </aura:if>
    </lightning:card>
</aura:component>

AccountNotificationsController.js:
({
subscribe : function(component, event, helper) {
component.set('v.notifications', []);
// Get the empApi component
const empApi = component.find('empApi');
// adding channel
         const channel = '/event/Account_Creation_Event__e';
         // Replay option to get new events
    const replayId = -1;
        // Subscribe to an platform event
        empApi.subscribe(channel, replayId, $A.getCallback(eventReceived => {
        // Process event (this is called each time we receive an event)
console.log('Received event ', JSON.stringify(eventReceived));
//Payload will have attribues(Fields) values from published plat form event
        console.log('Received event ', eventReceived.data.payload.Account_Name__c);
          const notifications = component.get('v.notifications');
          notifications.push(eventReceived.data.payload.Account_Name__c);
          component.set('v.notifications', notifications);
            component.set('v.evntRecieved',true);
    })).then(subscription => {
        // Confirm that we have subscribed to the event channel.
        // We haven't received an event yet.
            console.log('Subscribed to channel ', subscription.channel);
            // Save subscription to unsubscribe later
            //component.set('v.subscription', subscription);
    });
       
}
})


output:


Note: The lightning:empApi component is supported only in desktop browsers with web worker or shared worker support. For more information about web workers and browser support, see the Web Workers W3C specification and Using Web Workers in the Mozilla Developer Network documentation.

References:
https://www.youtube.com/watch?v=i5XSf_uF9XI
https://developer.salesforce.com/docs/atlas.en-us.platform_events.meta/platform_events/platform_events_intro.htm
https://developer.salesforce.com/docs/component-library/bundle/lightning:empApi/documentation
https://trailhead.salesforce.com/en/content/learn/modules/platform_events_basics


Friday, 27 March 2020

Wire an Apex Method with a Dynamic Parameter (Account Search)

Hi,

Here we are going to learn how to pass a parameter to an apex method using wire.

The following method takes a parameter "searchKey".

Apex Class:

public with sharing class AccountSearchCls { @AuraEnabled(cacheable=true) public static List<Account> findAccounts(String searchKey) { String key = '%' + searchKey + '%'; return [ SELECT Id, Name FROM Account WHERE Name LIKE :key LIMIT 10 ]; } }


Now let's see how our Lightning Web Component looks like and how can we pass parameter value to apex class:
The component’s JavaScript prefaces the value of the searchKey parameter with $ to indicate that it’s dynamic and reactive. 
It references a property of the component instance. If its value changes, the template rerenders.


AccountSearchLWC.JS

import { LightningElement,wire } from 'lwc';
import findAccounts from '@salesforce/apex/AccountSearchCls.findAccounts';
/** The delay used when debouncing event handlers before invoking Apex. */
const DELAY = 300;
export default class AccountSearchLWC extends LightningElement {
    searchKey = '';

    @wire(findAccounts, { searchKey: '$searchKey' })
    accounts;
    handleKeyChange(event) {
        // Debouncing this method: Do not update the reactive property as long as this function is
        // being called within a delay of DELAY. This is to avoid a very large number of Apex method calls.
        window.clearTimeout(this.delayTimeout);
        const searchKey = event.target.value;
        this.delayTimeout = setTimeout(() => {
            this.searchKey = searchKey;
        }, DELAY);
    }
}

AccountSearchLWC.HTML

<template>
    <lightning-card title="accountSearch" icon-name="custom:custom63">
        <div class="slds-m-around_medium">
            <lightning-input type="search" onchange={handleKeyChange} class="slds-m-bottom_small" label="Search" value={searchKey}></lightning-input>
            <template if:true={accounts.data}>
                <template for:each={accounts.data} for:item="account">
                    <p key={account.Id}>{account.Name}</p>
                </template>
            </template>           
        </div>
    </lightning-card>
</template>

AccountSearchLWC.js-meta.xml 

<?xml version="1.0" encoding="UTF-8"?>
<LightningComponentBundle xmlns="http://soap.sforce.com/2006/04/metadata">
    <apiVersion>48.0</apiVersion>
    <isExposed>true</isExposed>
    <targets>       
        <target>lightning__Tab</target>
    </targets>
</LightningComponentBundle>


Output:


Reference:


Friday, 6 March 2020

Navigation from JavaScript through visualforce page in Classic and lightning experience

Hi,

When you want to navigate to other pages or record pages from Javascript via Visualforce pages in both Salesforce Classic and Lightning Experience then replace the window.location with the compatible options.

When your visualforce page is going to be accessible from both classic and lightning experience you have to write your navigation in Javascript as shown below.

Here :UITheme.getUITheme()  will be useful whether this page is accessed in lighting experience or not.

<apex:page standardController="Account" lightningStylesheets="true"> 
   <script>
     function isLightningExperience(){
        if (UITheme.getUITheme() === 'Theme4d' || UITheme.getUITheme() === 'Theme4u'){
            sforce.one.editRecord('{!Account.Id}');
        } else {
            window.location='/{!Account.Id}/e';
        }
    }
   </script>   
   <apex:form >   
     <apex:pageBlock >
       <apex:pageBlockSection title="Edit">
         <apex:commandButton value="Edit"
          onclick="javascript:isLightningExperience();return false;"/>
       </apex:pageBlockSection>
     </apex:pageBlock>
   </apex:form>   
   <apex:detail />     
</apex:page>


Reference:
https://help.salesforce.com/articleView?id=lex_prepare_vf_window.htm&type=5
https://developer.salesforce.com/docs/atlas.en-us.pages.meta/pages/salesforce1_dev_jsapi_sforce_one.htm
https://developer.salesforce.com/blogs/developer-relations/2016/09/why-its-time-to-break-up-with-javascript-buttons-and-embrace-lightning.html

Create a recording using "lightning-record-form" in Lightning Web Component

Hi ,

Here we are going to learn how we can create a record without using apex controller:
By using "lightning-record-form" we can  do the following:

Load a Record

Create a Record

Update a Record


In our example we are going to see how can we create a recording using "lightning-record-form"

As usual let's  create lightning web component bundle with "HTML,JS,Meta" files.

accountCreateSampleComp.Html:

<template>
    <lightning-card  title="Account Creation">
        <p class="slds-p-horizontal_small">
                    <lightning-record-form object-api-name={objectApiName} fields={fieldList} onsuccess={handleAccountCreate}></lightning-record-form>
            </p>
    </lightning-card>
</template>

Here "object-api-name" - place your object name
"Fields" specify the field what you want to make available for record creation
"onsuccess" specify the method what has to be done when record is saved successfully

accountCreateSampleComp.js:
/* Import each field to use on your form. It recognize the whether the field is invalid or not at compile time itself .
Import platformShowToastEvent for showing toast Message
Import navigation for navigating to record page
*/

import { LightningElement } from 'lwc';
import Account_Name from '@salesforce/schema/Account.Name';
import Account_Type from '@salesforce/schema/Account.Type';
import Account_Industry from '@salesforce/schema/Account.Industry';
import { ShowToastEvent } from 'lightning/platformShowToastEvent';
import { NavigationMixin } from 'lightning/navigation';

export default class AccountCreateSampleComp extends NavigationMixin(LightningElement) {
    objectApiName = 'Account';
    fieldList = [Account_Name,Account_Type,Account_Industry];   
    handleAccountCreate(event){
        const evt = new ShowToastEvent({
            title: "Account Create",
            message: "Record ID: " + event.detail.id,
            variant: "success",
        });
        this.dispatchEvent(evt);
        this[NavigationMixin.Navigate]({
            type: 'standard__recordPage',
            attributes: {
                recordId: event.detail.id,
                objectApiName: 'Account',
                actionName: 'view'
            },
        });
    }

}

<?xml version="1.0" encoding="UTF-8"?>
<LightningComponentBundle xmlns="http://soap.sforce.com/2006/04/metadata">
    <apiVersion>48.0</apiVersion>
    <isExposed>true</isExposed>
    <targets>
        <target>lightning__Tab</target>
    </targets>
</LightningComponentBundle>

Here in meta file we are making our component available for Tab creation.


Ouput:



References:

What’s the difference between Einstein Article Recommendations and Suggested Articles?

How Does Einstein Article Recommendations Work? Einstein Article Recommendations helps support agents resolve customer cases efficiently by ...