Tuesday 28 September 2021

How to display formatted value in LWC component ?

1. Hide all numbers and display only 4 digits of SSN or credit card.

Declare a variable in Java Script controller that is being used in LWC component.

<lightning-formatted-number value={ssn}></lightning-formatted-number> 

 In the java script controller 

var num = '123456789234'; // you are getting SSN from apex class

ssn = num.slice(-4).padStart(num.length,'*');

Console.log('ssn',ssn);



2. Append . to the end of string.

var charString = 'Learning Salesforce';

charString.padEnd(30,'.');


3. Append Currency Symbol 

var testNum = 123445.34;

testNum.toLocaleString('en-IN',{style:"currency",currency:'INR'});

testNum.toLocaleString('en-US', { style: 'currency',currency:'USD'})

testNum.toLocaleString('de-DE', { style: 'currency', currency: 'EUR' })

testNum.toLocaleString('en-GB', { style: 'currency', currency: 'EUR' })


4. Display percentage value

var testNum = 0.2;

testNum.toLocaleString('en-US', { style: 'percent'})





Thursday 23 September 2021

How to create Chatter Post and Notification from Flow ?


 It is very easy to create chatter post using process builder, there are many cool articles there.

https://automationchampion.com/2015/10/03/getting-started-with-process-builder-part-47-mention-a-related-user-in-a-post-to-chatter-action/

This post is in regards to create notification and chatter post using flow.

Use Case :We have downstream system which needs opportunity data from salesforce, we have fire and forgot integration approach to integrate both systems. Now on successful response we need to notify users that Opportunity has been pushed and one Id has been created in Downstream system.

Chatter Post 

1. Create Record Triggered Flow and Add your entry condition

2. Add action element

3. Select Messaging and Action as Post to Chatter

4. Create Text Template Type variable and Add your chatter message, 

Even you can tag chatter post to certain users. Sometimes we can see <P><B> in the message, please remove that tag when we view message in text format in Field.

Hi @[{!$Record.OwnerId}] Resident {!$Record.Name} has been pushed .@[{!$Record.Liaison__c}] @[{!UserRec.Id}]

5. Populate Message value as Text Template variable 

6. Populate Target Name or Id as Opportunity Record Id, so that chatter post will be added as feed item to record.

Chatter Post - 



Custom Notification

1. Define custom notification Type

2. Add Getrecords to get Notification Type Id


3. Add Action element. Select Notifications and Action as "Send Custom Notification"

4. Populate fields 

Custom Notification Type ID - Populate record Id got from step 2 Get records

Notification Body - Create Constant Field and text

Notification Title - "Matrix Update"

Recipient IDs - Collection Variable add all user Id, or chatter group Ids 

Target Id - opportunity Record id





Here is total flow 


When user log in to salesforce, they will see one unread message in the bell icon



Please let me know by adding comments how this is helpful for your use case.





Thursday 16 September 2021

How to have Chaining Promises in Lighting Component ?

We may need to call multiple apex function from aura component, each function is dependent to other function. In that case we may have call promise function inside another.

Here is the sample code

@AuraEnabled
public static Opportunity getOpportunity(String opptyId){
        return [select id,name,stagename from Opportunity where id='opptyId']
 }

@AuraEnabled
public static Boolean checkFormAttached(String opptyId){
        Boolean isNotAttached = true;
        set<String> setOfNames = new set<String>
{'Admission Notification','EligibilitySummary','BAForm'};
        List<ContentDocumentLink> contLinks = [SELECT id,contentdocument.Title,
LinkedEntityId FROM ContentDocumentLink 
                                               WHERE LinkedEntityId =:opptyId 
                                               AND contentdocument.Title IN:setOfNames];
        return contLinks.size()>0;
 }

Java script controller
({ doInit : function(component, event, helper){
        
        let checkAttachment = helper.checkAttachment(component, event, helper, false);
        
checkAttachment.then(function(result){
            // if result is true then call function
            if(result){
                
                let getoppy = helper.getopportunity(component, event, helper, false);
                  
                getoppy.then((globalResults) => {
                }).catch((error) => {
                     
                let toast = {title: "Error", type: "error", message: "An error occurred while searching for matching residents."}; helper.showToast(toast); component.set("v.closeModal", true); return;
});
}
});
}
})

Helper class
({
checkAttachment : function(component, event, helper){
        console.log('checkAttachment called');
         let opptyId = component.get("v.recordId");
         console.log('opptyId ',opptyId);
        //check attachments
    let checkAttachments = helper.executeAction(component, "c.checkFormAttached", {"opptyId":opptyId});
return checkAttachments.then((results) =>{
             console.log('results 39',results);
             if(!results){
              helper.showToast({type: "error",
title: "Attachment Missing",
message: "Please attach at least one of the following – Admission Notification, BA Form, Eligibility Summary"});
component.set("v.closeModal", true);
component.set("v.isLoading", false);
return false;
            }else{
                console.log('results 46',results);
                return true;
            }
         });
        
    },
executeAction: function(component, actionName, params) { return new Promise(function(resolve, reject) { var action = component.get(actionName); action.setParams(params); action.setCallback(this, function(response) { if (component.isValid() && response.getState() === 'SUCCESS') { resolve(response.getReturnValue()); } else { reject(response.getError()[0]); } }); $A.enqueueAction(action); }); },
getResidents : function(component, event, helper){
         let getoppy= helper.executeAction(component, "c.getOpportunity", {"opptyId":opptyId});
return
getoppy.then((results) => {
            if(results){
                return results;
}else{return null;}
});
}
})

Wednesday 15 September 2021

How to float text in lightning web component ?

 Use Case - Publish message to all users in salesforce in Home Page or any other record page.

                   1. It should be easily configurable.

                   2. We can stop displaying message whenever we want from a configuration. It should have Start Time and End Time.

Here is my approach to achieve the same.

1. Create a custom Object Salesforce_News__c. custom fields - Start_Date__c , End_Date__c, Active__c and Message__c



2. Create record page for  Salesforce_News__c and add the page to application. 

3. Create a permission set "Salesforce News configure"  which will have Create,Edit access to object Salesforce_News__c.

4. Assign permission to user who is going to configure message.

5. Create LWC component 

6. Add LWC component to Home Page.

Here is LWC component code.

<template>
<marquee> 
<div class="slds-clearfix" if:true={showMessage}>
  <div class="slds-float_left">
    <p>
    <b><span style="color:red">Important Note : </span>
    <span style="color:white;font-family: Arial, Helvetica, sans-serif;
 font-size: medium;">{newsTicket.Message__c}
    </span></b>
    </p>
  </div>
</div>
</marquee>
</template>

Javascript
import { LightningElement,api } from 'lwc';
import showMessage from '@salesforce/apex/NewsTickerCls.showMessage';
export default class NewsTicker extends LightningElement {
    showMessage;
     @api newsTicket;
     connectedCallback(){
         this.showMessage = false;
         showMessage()
         .then(res => {
             if(res !=null){
                  this.showMessage = true;
                  this.newsTicket = res;
                  console.log('this.newsTicket--',this.newsTicket);
             }
            
             
         });
         
     }
     
}

XML code
<?xml version="1.0" encoding="UTF-8"?>
<LightningComponentBundle xmlns="http://soap.sforce.com/2006/04/metadata">
    <apiVersion>52.0</apiVersion>
    <isExposed>true</isExposed>
     <targets>
        <target>lightning__RecordPage</target>
        <target>lightning__AppPage</target>
        <target>lightning__HomePage</target>
    </targets>
</LightningComponentBundle>

Apex class
public with sharing class NewsTickerCls { @AuraEnabled public static Salesforce_News__c showMessage(){ Datetime currTime = System.now(); List<Salesforce_News__c> currentMessag = [Select Message__c
from Salesforce_News__c
where Active__c = true AND start__c <:currTime AND End__c >: currTime limit 1]; If(!currentMessag.isEmpty()){ return currentMessag[0]; } return null; } }
Test class
@isTest
private class NewsTickerClsTest {

   @isTest  
    static void dotest(){
        Salesforce_News__c news = new Salesforce_News__c();
        news.Message__c = 'Test Message';
        news.start__c = System.today()-1;
        news.End__c = System.today()+1;
        news.Active__c = true;
        Insert news;
        test.startTest();
        Salesforce_News__c result = NewsTickerCls.showMessage();
        System.assert(result !=null);
        test.stopTest();
            
    }
}



Tuesday 14 September 2021

How to get Salesforce lookup field object id using javascript ?

 When we  add a look input field then salesforce add a hidden field to capture Id. We need to get value from hidden field to get record Id.

For example 

<apex:inputfield value="{!Custom__c.lookField__c}"  id="lookupfieldId" />

<script type="text/javascript">

function getLookupId()

{

var fieldId = document.getElementById('{!$Component.lookupfieldId}_lkid').value;

alert('id'+fieldId );

}

</script>

We can also inspect field to get Id use it 

var fieldId =  document.getElementById('{!$Component.pageId:formId:pgBlkId:pgBlkSecId1:lookupfieldId}_lkid').value;

Monday 13 September 2021

How to change aura component bundle version ?

Source org and target org should be in compatible version to have successful deployments There are sometime org which will have higher version that might not supported in production. This could happen when a particular instance is in release preview and if we add new component in that org. That new component will have higher salesforce API version.

While deploying we might get errors. Changing version in Apex and VF page is easy. 


Setup-->Apex Class-->Click Edit next to class -->Version Settings -->Change version


How to change version number of Aura Component ?

1. Developer console Query Editor 

2. Query - SELECT Id, DeveloperName, ApiVersion, Description FROM AuraDefinitionBundle WHERE DeveloperName = 'your component Name'

3. Change version in the results

4. Click Save




Sunday 12 September 2021

How to get list of users added to a queue in Apex ?

 There is no separate objects to store queue name and all queue members. They are mapped to Group and Group Member respectively. Queues are stored as records in the table Group with 'Type' as "Queue". 

Select Id from Group where type='Queue' and Name='Queue Name' - This query will return Id of queues.

Use above query results (Id)  in the query [Select UserOrGroupId From GroupMember where GroupId =:grpIdset] to fetch all the users or groups which are members of the required queue. 

We can also write both query combing 

SELECT UserOrGroupId, COUNT( Id ) FROM GroupMember WHERE GroupId IN ( SELECT Id FROM Group WHERE Type = 'Queue' ) GROUP BY UserOrGroupId
 
For User level
SELECT UserOrGroupId, COUNT( Id ) FROM GroupMember WHERE UserOrGroupId =: userfinfo.getUserid() AND GroupId IN ( SELECT Id FROM Group WHERE Type = 'Queue' ) GROUP BY UserOrGroupId 

We know Queue can be created for different objects. We have a section names supported objects, where we can select objects names.

To know which objects this queue contains then we have another standard objec

QueueSobject : - Represents the mapping between a queue Group and the sObject types associated with the queue, including custom objects.

https://developer.salesforce.com/docs/atlas.en-us.api.meta/api/sforce_api_objects_queuesobject.htm

SELECT QueueId FROM QueueSobject where SobjectType in ('ObjectName','ObjectName2','ObjectName3')






Thursday 9 September 2021

How to clone Lead record in apex ?

 We have standard clone button where we can clone only lead record, what if we need to clone all the child records and attachments along with Lead then apex is only options.

1. Define Quick Action "Clone", call lightning component.

2. Change layout add custom clone button in the place of Standard clone button.

We have to make sure, if any custom fields added in Lead in future then cloned should have that new field populated  and should be able to be converted.  That being said we cant hardcode field name. We have to make it dynamic.

Here is code block to get all fields dynamically in SOQL.

// This is the set where all fields name will be stored
Set<String> fieldNames = new Set<String>();
Map<StringSchema.SObjectField> fieldMap = Lead.sObjectType.getDescribe().fields.getMap();
// Get all of the fields on the object
for(String sFielName:fieldMap.keySet()){
  fieldNames.add(sFielName);
}
String fieldsName = String.join((Iterable<String>) fieldNames, ',');
// Build a Dynamic Query String.
String soqlQuery = ' SELECT ' + fieldsName + ' FROM Lead Where Id =: leadRecId';
system.debug('soqlQuery---'+soqlQuery);

The above code has one caveat, all the fields will be included, for example IsConverted field also be updated
which will stop lead conversion, we would not want that.
We have to tweak above code little bit not to include some of the fields.

Set<String> excludedFieldsName = new Set<String>{'isconverted','converteddate','convertedaccountid','convertedcontactid',
            'convertedopportunityid','createdbyid','lastmodifieddate','createddate','lastmodifiedbyid','systemmodstamp',
            'lastactivitydate','lastvieweddate','lastreferenceddate','ownerid'};

for(String sFielName:fieldMap.keySet()){
    if(excludedFieldsName.contains(sFielName)) continue;
  fieldNames.add(sFielName);
}

Now query is ready to pull lead record with desired fields , Lets talk about clone method. 

In salesforce the sObject class has a clone method that can be used. When using the clone method, there are two types of cloning: a shallow clone or a deep clone. Clone method has 4 parameters. We will get very good article to talk bout each parameters.

clone(Boolean preserveId, Boolean isDeepClone, Boolean preserveReadonlyTimestamps, Boolean preserveAutonumber)

https://www.levelupsalesforce.com/clone-method-in-salesforce

Here is my code to clone Lead only the fields available in SOQL.

List<Lead> Leads = Database.query(getSOQLStament());
System.debug('Leads--'+Leads);
if(!Leads.IsEmpty()){
    Lead newLead = Leads[0].clone(false, true);
    newLead.status = 'Active';
    Insert newLead;
    System.debug('newLead--'+newLead.id);
}

private static String getSOQLStament(){
        // This is the object for which we required data.
        Set<String> fieldNames = new Set<String>();
        Set<String> excludedFieldsName = new Set<String>{'isconverted','converteddate','convertedaccountid','convertedcontactid',
            'convertedopportunityid','createdbyid','lastmodifieddate','createddate','lastmodifiedbyid','systemmodstamp',
            'lastactivitydate','lastvieweddate','lastreferenceddate','ownerid'};
    Map<StringSchema.SObjectField> fieldMap = Lead.sObjectType.getDescribe().fields.getMap();
        // Get all of the fields on the object
        for(String sFielName:fieldMap.keySet()){
            if(!excludedFieldsName.contains(sFielName)){
                fieldNames.add(sFielName);
            }
             
        }
        String fieldsName = String.join((Iterable<String>) fieldNames, ',');
        // Build a Dynamic Query String.
    String soqlQuery = ' SELECT ' + fieldsName + ' FROM Lead Where Id =: leadRecId';
        system.debug('soqlQuery---'+soqlQuery);
        return soqlQuery;

    } 



  

How to close modal dialog in Lighting component ?

 Lightning Web Components

Lightning Web Components are supported in Quick Action after 21, Here is the code to close popup.

First Import library 

import { CloseActionScreenEvent } from 'lightning/actions';

Dispatch event when we want to close popup

this.dispatchEvent(new CloseActionScreenEvent());

XML code
<targets>
  <target>lightning__RecordAction</target>
</targets>
<targetConfigs>
  <targetConfig targets="lightning__RecordAction">
    <actionType>ScreenAction</actionType>
  </targetConfig>
</targetConfigs>

Lightning Aura Components
It is very easy to close aura modal, we need
$A.get("e.force:closeQuickAction").fire();

Here is controller code 
({
closeMethodInAuraController : function(component, event, helper) {
$A.get("e.force:closeQuickAction").fire();
}
})

Lightning Aura Components + Lightning LWC Components
When LWC component is wrapped inside aura component.

1. Dispatch an event from LWC component

 const closeQA = new CustomEvent('close');
        // Dispatches the event.
        this.dispatchEvent(closeQA);

2. Have Listener defined in Aura to close popup. 
<c:lwcComponent onclose="{!c.closeMethodInAuraController}" recordId="{!v.recordId}"/>

Aura Component 
<aura:component implements="force:lightningQuickActionWithoutHeader,force:hasRecordId">

    <aura:html tag="style">
.cuf-content {
  padding: 0 0rem !important;
}
.slds-p-around--medium {
  padding: 0rem !important;
}
.slds-modal__content{
  overflow-y:hidden !important;
  height:unset !important;
  max-height:unset !important;
}
</aura:html>
    <c:cloneLead onclose="{!c.closeMethodInAuraController}" recordId="{!v.recordId}"/>
</aura:component>

Controller
({ closeMethodInAuraController : function(component, event, helper) { $A.get("e.force:closeQuickAction").fire(); } })

 <aura:html> code just make background style.

Wednesday 8 September 2021

How to load image in LWC component ?

 1. First Load your image in Static Resource. Say name - Financial_ComingSoon 

 2. Import @salesforce/resourceUrl

here is the syntax 

import Financial_ComingSoon from '@salesforce/resourceUrl/Financial_ComingSoon';

3. Declare a variable in export function
financeLogoUrl = Financial_ComingSoon;

4. Refer financeLogoUrl in component. StaticResourceImageLWCExample
<template>
    <lightning-card title="My Banking and Financial ">
        <div class="slds-m-around_medium">
            <img src={financeLogoUrl}>
           
        </div>
</template>

Here is controller code
import { LightningElement } from 'lwc';
import Financial_ComingSoon from '@salesforce/resourceUrl/Financial_ComingSoon';
export default class StaticResourceImageLWCExample extends LightningElement {
    financeLogoUrl = Financial_ComingSoon;
}

Component 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__AppPage</target>
        <target>lightning__RecordPage</target>
        <target>lightning__HomePage</target>
    </targets>
</LightningComponentBundle>