Thursday, 30 June 2022

Salesforce Dynamic Related List in the lightning app builder

With the Salesforce Summer'22 release, Related lists can now be customized straight from the Lightning App Builder rather than the page layout editor with Salesforce's new Dynamic Related List.

What does salesforce's Dynamic Related List mean?
Dynamic Related Lists is the newest feature in the Summer’22 release, With the use of Dynamic Related List you can customize the related list directly in Lightning App Builder. By customizing a related list you can set how many records to display, which fields and actions to appear, and set filters on the related list.

Dynamic Related List – Single Component
The following characteristics set the dynamic related list - single component apart from the static related list component.

  • Define Related List Label and type of list
  • Configure Number of Records to Display 
  • Show/hide List View Action Bar
  • Define Related List Filters
  • Configure Actions 
  • Set Component Visibility

    Let's see how to add Dynamic Related List into page.

    Add Dynamic Related Lists in Lightning Page using Lightning App Builder 
    Follow the below steps to add Dynamic Related List - Single component one a Lightning Record Page, Here we are adding Dynamic Related List on a Account record page.

    • Click on Setup.
    • Click on Object Manager, Select Account.
    • Select Lightning Record Page, Click on Account Record Page.
    • Click On Edit.
    • Drag and drop Dynamic Related List – Single on the canvas.
    • After adding Dynamic Related List – Single, Configure all the properties which is shown in the below image.

    Dynamic Related List - Single
    • Clock on Save and Activate.

    Click Here to see release notes on Dynamic Related List.

    If you have any questions you can reach out our Salesforce Consulting team here.

    Thursday, 23 June 2022

    Override Lightning Input Field Label In Lightning Web Component

    SCENARIO

    While working on one of the requirements for a Health sector project for a client based out of Atlanta, GA, there was a requirement to set custom labels in the place of fields standard labels in Lightning Web Component.

    CHALLENGE

    In Lightning Web Component, By using lightning-record-edit-form with lightning-input-field tag we can not set a custom label for lightning-input-field.

    APPROACH

    By hiding the label of a lightning input field and setting a custom label for a lightning input field we can set a custom label. Let's take dive into it.

    The field label is automatically obtained from the metadata description of the field when lightning-input-field is used with lightning-record-edit-form. For example, if the field's label is First Name and you send the field's API name to the lightning-input-field component, the component will display First Name as the field label.

    Let's look with the example, For contact object fields First Name, Last name and Email need to set custom labels as Contact First Name, Contact Last Name, Contact Email. Below is a code to override field labels.

    Here we have assigned an id to the lightning-input-field component and used variant attribute with value label-hidden. while define the label-hidden, it hides the actual label of the lightning input field.

    The custom label value from the label tag will be passed using the id that we have given to the lightning-input-field component.

    OUTPUT





    CONCLUSION

    By simply hiding actual label of the lightning input field and adding a custom label tag, We can override lightning input field label.

    If you have any questions you can reach out our Salesforce Consulting team here.

    Thursday, 16 June 2022

    Delete Inactive Picklist Values in Bulk (Beta)

    With the Salesforce summer’22 release, we can bulk delete unused inactive picklist values. Before the release of summer’22, custom picklists with many inactive values were difficult to maintain because we can delete inactive ones at a time. let’s take a look in brief.

    Clean Up Inactive Picklist Values (Beta)

    Managing inactive picklist values and establishing restrictions on the number of inactive values for custom picklists can help your Salesforce org run more smoothly and efficiently. You can bulk delete inactive unused values from a picklist if there are a lot of them.

    Below are the steps to avail of this feature in your org.

    Active Bulk delete inactive picklist values(Beta) option

    • Click Setup.
    • In the Quick Find box, type Picklist Settings.
    • Activate Bulk Delete Inactive Picklist Values (Beta) option.

    Bulk Delete Inactive Picklist Values
    Now, we will get the option to bulk delete inactive unused picklist values.

    Below are the rules that apply while bulk deleting picklist values.

    Rules
    • This feature is available only for custom picklist fields on an object. It’s not available for standard or multi-select picklist fields.
    • This feature is only for picklist fields that have defined values. It’s not available for picklist fields that use a global value set.
    • This feature deletes inactive, unused picklist values. If a picklist value is inactive but still referenced in a record, the value isn’t deleted.
    • After you delete unused values, if a picklist is unbound and the total number of inactive values falls below the limit, the field is set to a bound picklist.
    • While the job that deletes inactive values runs, these actions are unavailable on that picklist field: Activate, Activate Selected, Deactivate, Deactivate Selected, Delete, Delete Selected, Replace, and Replace Selected. The buttons are enabled, but an error message is returned when you click them.
    • While the job that deletes inactive values runs, changes to the picklist field via Metadata API are unavailable. You can retrieve data from the field, but you can’t: create a picklist value, update the field or its values, delete the field or its values, or deploy the field.

    Follow the below steps to delete all inactive unused values from a picklist.

    • Click Setup.
    • Click on Object Manager, and select your Object.
    • Click on Fields & Relationships, and click the picklist field. In the Picklist Values Used section, you can see how many inactive picklist values the field has.
    • From the Inactive Values section of the picklist field, click Delete Unused Values.

    Delete unused values

    After all of the picklist values have been deleted, you will receive an email indicating whether or not the deletion was successful. The email is sent to the user whose email address was used to initiate the deletion.

    Click here to see release notes of summer'22 on Clean Up Inactive Picklist Values (Beta) 

    If you have any questions you can reach out our Salesforce Consulting team here.

    Thursday, 2 June 2022

    Using the Button, send the Record Id to the Flow

    Scenario :
    While working on one of the requirements for a health sector project for a client based out of MelbourneAustralia there was a requirement to avail current record id in a flow by clicking a button for further actions.

    Approach : 
    The client wants a custom button on the Contact record page to launch the flow and avail the record id in a flow.

    By passing the record id in a flow URL we can get the record id in a flow. Let's see with the example. 

    Follow the below steps to create a flow.

    Screen Flow :

    Step 1:-  Define flow properties.
    • Click Setup.
    • In the Quick Find box, type Flows.
    • Select Flows then click on the New Flow.
    • Select the Screen Flow option and click on Next and configure the flow as follows:
      • How do you want to start building: Freeform
    Step 2:- Flow variable
    Define recordId Text variable to store Record Id.
    • Under Toolbox, select Manager and click on New Resource.
    • Input the following information,
      • Resource Type - Variable
      • API Name - recordId
      • Data Type - Text
      • Allow multiple values (collection) - Uncheck 
      • Available for InputCheck
    • Click Done.
    recordId variable

    Step 3:- Create Screen Element
    We will create a screen element to display Record Id in this step.
    • Under Toolbox, select Elements. Drag and drop Screen onto the canvas.
    • Fill following Information on Screen Properties.
      • Enter Label the API Name will auto-populate.
      • under Components, select Display Text, Drag, and drop Display Text onto the screenfill the following details.
        • API Name - Show_recordId
        • Insert a resource - {!recordId}
    • Click Done.
    • Connect start element to screen element.
    Screen element

    Our Flow is complete, Save and Activate the Flow. below is a diagram of the Flow.

    Flow Diagram

    Flow diagram

    Now, Our Flow looks good. Let's create a custom button on the contact object and add a button on the contact page layout.

    Custom Button

    Follow the below steps to create a button on the contact object.

    Step 1: 
    • Go to Setup > Object Manager
    • Select a Contact Object
    Step 2:
    • Go to Buttons, Links and Actions
    • Click on New Button or Link 
    Step 3:
    Fill in the below details.
    • Label - Run Flow
    • Name - Run_Flow
    • Display Type - Detail Page Button
    • Behavior - Display in new window
    • Content Source - URL
    • Fill the below URL in the text area
    /flow/Get_RecordId_In_Flow_Example?recordId={!Contact.Id}&retURL={!Contact.Id}
    

    Click on the Save button.
    Custom button

    Add the custom button to the page layout

    Below are the steps to add the custom button to the contact page layout.
    • Go to Page Layout. Select the edit option.
    • Select Mobile and Lightning Experience Actions from the panel.
    • Drag and drop Run Flow custom button to the Mobile and Lightning Experience Actions section.
    • Click Save.

    Contact page layout
    Output


    Click here to see the Trailhead badge on Distribute the Flow with a Custom Button for more information.

    If you have any questions you can reach out our Salesforce Consulting team here.

    Thursday, 26 May 2022

    Setting up merge fields and sending emails using email template on the custom object through apex


    SCENARIO

    While working on one of the requirements for a Service sector project for a client based out of Atlanta, GA, there was a requirement to send an email using an email template where the related entity type was the custom object.

    CHALLENGE

    In SingleEmailMessage, if we set template-id (using setTemplateId), then target object id is required. setTargetObjectId() can accept contact, lead, user or person account id only. We cannot pass the custom object id in the parameter of setTargetObjectId() - reference link. Also, the custom object is not having any relationship to any of these standard objects.

    APPROACH

    With a little magical Apex hand-waving, we can indeed send emails using custom email templates.

    The key thing we used here is Salesforce doesn't send an email immediately when the sendEmail() method is executed, instead, Salesforce waits for the very end of the transaction. If we roll back the transaction, Salesforce doesn't send the email at all.

    Below is the text value of the email template having some merge fields that we want to populate automatically,

    Hi {{{Sourcing__c.Full_Name__c}}},
    
    Good afternoon, I hope you are having a great day, and that this email finds you well. 
    
    I just wanted to reach out to follow up with you about your application for one of
    our Entry-Level IT Career Opportunities. We are very interested in speaking with you.
    
    Our initial phone call takes less than 10 minutes. You can reach me on my direct line,
    {{{Sender.Phone}}} If for some reason I do not answer please leave a voice mail
    and reply to this email. 
    
    Regards,
    {{{Sender.Signature}}}
    

    Below is a code we used for sending emails,

    public class SendEmailSourcing{
        
        public void sendEmailMessage(){
    	// Fetching email template
            EmailTemplate emailTemplate = [SELECT Id, DeveloperName, Subject, HtmlValue, Body
                                           FROM EmailTemplate WHERE Name = '1st Call - Email' LIMIT 1];
    									   
    	// Picking a dummy contact where email is not null
            Contact con = [SELECT Id, Email FROM Contact WHERE email <> NULL LIMIT 1];    
            
            List<Messaging.SingleEmailmessage> emailMessages = new List<Messaging.SingleEmailMessage>();
            List<Messaging.SingleEmailmessage> emailMessagesToSend = new List<Messaging.SingleEmailMessage>();
            Messaging.SingleEmailmessage email = new Messaging.SingleEmailmessage();  
            
    	// For every sourcing record, creating email message and adding it to the list of email messages
            for (Sourcing__c sourcing :  sourcingList) {                
    		email = new Messaging.SingleEmailmessage();
    		email.setTemplateId(emailTemplate.Id);
    		email.setTargetObjectId(con.Id);
    		email.setWhatId(sourcing.Id);
    		email.setToAddresses(new List<String>{sourcing.Email__c});
    		email.setTreatTargetObjectAsRecipient(false);
    		email.setUseSignature(false);
    		emailMessages.add(email);
    	}       
            
    	// Setting save point to rollback the transaction after sending email message
            Savepoint sp = Database.setSavepoint();
            Messaging.sendEmail(emailMessages);
            Database.rollback(sp);
            
    	// Copying content of the each email message that we just sent using sendEmail() and rolled back
    	// and sending these new messages
            for (Messaging.SingleEmailMessage singleEmail : emailMessages) {
    		email = new Messaging.SingleEmailMessage();
    		email.setToAddresses(singleEmail.getToAddresses());
    		email.setPlainTextBody(singleEmail.getPlainTextBody());
    		email.setHTMLBody(singleEmail.getHTMLBody());
    		email.setSubject(singleEmail.getSubject());
    		email.setWhatId(singleEmail.getWhatId());
    		email.setUseSignature(false);
    		email.setSaveAsActivity(true);
    		emailMessagesToSend.add(email);
            }
    		
            Messaging.sendEmail(emailMessagesToSend);  
        }
    	
    }
    

    In the above code, first, we created email message for each sourcing record and added it to the list of email messages. Then trying to send email messages in a transaction that can be rolled back.

    After rolling back the transaction, we are iterating through all the emails we just sent and are copying the content of those emails into another list of emails.

    That newly created list is then used to send the emails.

    CONCLUSION

    Using Apex effectively and rolling back the transaction, we are able to set merge fields and send email messages using email templates where a related entity type is a custom object.

    If you have any questions you can reach out our Salesforce Consulting team here.

    Thursday, 19 May 2022

    Lightning Web Component - Making custom dual list box with same functionality as standard Lightning-dual-listbox

    SCENARIO

    While working on one of the requirements for a Banking sector project for a client based out of London, UK there was a requirement to make a custom-made dual list box instead of the standard lightning-dual-listbox.

    CHALLENGE

    The client wanted a custom dual listbox instead of a standard because they wanted to implement different functionality on each button which was not possible in the standard lightning-dual-listbox.

    APPROACH

    First, We created a custom dual list box having the same UI as standard lightning-dual-listbox having 2 list boxes and 4 buttons (right, left, up and down) using the code provided by the standard lightning design system.

    We made sure that multiple values can be added from the available to the selected list box and vice-versa.

    Refer to the below code that we used to create custom dual listbox.

    customDualListBox.html

    <template>
        <lightning-card title="Custom Dual List Box" icon-name="custom:custom63">
            <div class="slds-form-element slds-box" role="group" aria-labelledby="picklist-group-label">
                <span id="picklist-group-label" class="slds-form-element__label slds-form-element__legend">Select
                    Options</span>
                <div class="slds-form-element__control">
                    <div class="slds-dueling-list">
                        <div class="slds-assistive-text" id="drag-live-region" aria-live="assertive"></div>
                        <div class="slds-assistive-text" id="option-drag-label">Press space bar when on an item, to move it
                            within the list. Cmd/Ctrl plus left and right arrow keys, to move items between lists.</div>
                        <div class="slds-box">
                            <!-- Available Options -->
                            <div class="slds-dueling-list__column slds-border_right">
                                <span class="slds-form-element__label" id="label-107">Available Options</span>
                                <div class="slds-dueling-list__options slds-border_right">
                                    <ul aria-describedby="option-drag-label" aria-labelledby="label-107"
                                        aria-multiselectable="true" class="slds-listbox slds-listbox_vertical"
                                        role="listbox">
                                        <template for:each="{availableOptions}" for:item="option">
                                            <li class="slds-listbox__item" data-value="{option.value}" key="{option.value}"
                                                onclick="{handleSelectionForAvailable}">
                                                <div data-val="{option.value}"
                                                    class="slds-listbox__option slds-listbox__option_plain slds-media slds-media_small slds-media_inline">
                                                    <span class="slds-media__body">
                                                        <span title="English" class="slds-truncate">{option.label}</span>
                                                    </span>
                                                </div>
                                            </li>
                                        </template>
                                    </ul>
                                </div>
                            </div>
                            <!-- Right left buttons -->
                            <div class="slds-dueling-list__column">
                                <button class="slds-button slds-button_icon slds-button_icon-container"
                                    title="Move Selection to Second Category" onclick="{handleRightClick}">
                                    <lightning-icon icon-name="utility:right" size="x-small" alternative-text="right"
                                        title="right"></lightning-icon>
                                    <span class="slds-assistive-text">Move Selection to Second Category</span>
                                </button>
                                <button class="slds-button slds-button_icon slds-button_icon-container"
                                    title="Move Selection to First Category" onclick="{handleLeftClick}">
                                    <lightning-icon icon-name="utility:left" size="x-small" alternative-text="left"
                                        title="left"></lightning-icon>
                                    <span class="slds-assistive-text">Move Selection to First Category</span>
                                </button>
                            </div>
                            <!-- Selected Options -->
                            <div class="slds-dueling-list__column">
                                <span class="slds-form-element__label" id="label-108">Selected Options</span>
                                <div class="slds-dueling-list__options">
                                    <ul aria-describedby="option-drag-label" aria-labelledby="label-108"
                                        aria-multiselectable="true" class="slds-listbox slds-listbox_vertical"
                                        role="listbox">
                                        <template for:each="{selectedOptions}" for:item="option">
                                            <li class="slds-listbox__item" data-value="{option.value}" key="{option.value}"
                                                onclick="{handleSelectionForSelected}">
                                                <div data-val="{option.value}"
                                                    class="slds-listbox__option slds-listbox__option_plain slds-media slds-media_small slds-media_inline">
                                                    <span class="slds-media__body">
                                                        <span title="selected" class="slds-truncate">{option.label}</span>
                                                    </span>
                                                </div>
                                            </li>
                                        </template>
                                    </ul>
                                </div>
                            </div>
                            <!-- Up down buttons -->
                            <div class="slds-dueling-list__column">
                                <button class="slds-button slds-button_icon slds-button_icon-container"
                                    title="Move Selection up" onclick="{handleUpClick}">
                                    <lightning-icon icon-name="utility:up" size="x-small" alternative-text="up" title="up">
                                    </lightning-icon>
                                    <span class="slds-assistive-text">Move Selection up </span>
                                </button>
                                <button class="slds-button slds-button_icon slds-button_icon-container"
                                    title="Move Selection down" onclick="{handleDownClick}">
                                    <lightning-icon icon-name="utility:down" size="x-small" alternative-text="down"
                                        title="down"></lightning-icon>
                                    <span class="slds-assistive-text">Move Selection down </span>
                                </button>
                            </div>
                        </div>
                    </div>
                </div>
            </div>
        </lightning-card>
    </template>
    

    customDualListBox.js

    import { LightningElement, track } from "lwc";
    export default class customDualListBox extends LightningElement {
        @track availableOptions = [
            { label: "Option 1", value: "o1" },
            { label: "Option 2", value: "o2" },
            { label: "Option 3", value: "o3" },
            { label: "Option 4", value: "o4" },
            { label: "Option 5", value: "o5" },
            { label: "Option 6", value: "o6" },
            { label: "Option 7", value: "o7" },
        ];
    
        @track selectedAvailableOptions = [];
        @track selectedOptions = [];
        @track selectedSelectedOptions = [];
    
        handleSelectionForAvailable(event) {
            if (this.selectedAvailableOptions.filter((option) => option === event.currentTarget.dataset.value).length) {
                this.selectedAvailableOptions = this.selectedAvailableOptions.filter((option) => option !== event.currentTarget.dataset.value);
                event.currentTarget.setAttribute("aria-selected", "false");
            } else {
                this.selectedAvailableOptions.push(event.currentTarget.dataset.value);
                event.currentTarget.setAttribute("aria-selected", "true");
            }
        }
    
        handleSelectionForSelected(event) {
            if (this.selectedSelectedOptions.filter((option) => option === event.currentTarget.dataset.value).length) {
                this.selectedSelectedOptions = this.selectedSelectedOptions.filter((option) => option !== event.currentTarget.dataset.value);
                event.currentTarget.setAttribute("aria-selected", "false");
            } else {
                this.selectedSelectedOptions.push(event.currentTarget.dataset.value);
                event.currentTarget.setAttribute("aria-selected", "true");
            }
        }
    
        handleRightClick() {
            var tempSelectedOptions = JSON.parse(JSON.stringify(this.selectedAvailableOptions));
            if (tempSelectedOptions.length) {
                for (let selectedOption of tempSelectedOptions) {
                    this.selectedOptions.push(...this.availableOptions.filter((option) => option.value === selectedOption));
                    this.availableOptions = this.availableOptions.filter((option) => option.value !== selectedOption);
                }
            }
            this.selectedAvailableOptions = [];
        }
    
        handleLeftClick() {
            var tempSelectedOptions = JSON.parse(JSON.stringify(this.selectedSelectedOptions));
            if (tempSelectedOptions.length) {
                for (let selectedOption of tempSelectedOptions) {
                    this.availableOptions.push(...this.selectedOptions.filter((option) => option.value === selectedOption));
                    this.selectedOptions = this.selectedOptions.filter((option) => option.value !== selectedOption);
                }
            }
            this.selectedSelectedOptions = [];
        }
    
        handleUpClick() {
            var tempSelectedOptions = JSON.parse(JSON.stringify(this.selectedSelectedOptions));
            if (tempSelectedOptions.length == 1) {
                for (let i = 0; i < this.selectedOptions.length; i++) {
                    if (i != 0 && this.selectedOptions[i].value === tempSelectedOptions[0]) {
                        [this.selectedOptions[i], this.selectedOptions[i - 1]] = [this.selectedOptions[i - 1], this.selectedOptions[i]];
                        break;
                    }
                }
            }
        }
    
        handleDownClick() {
            var tempSelectedOptions = JSON.parse(JSON.stringify(this.selectedSelectedOptions));
            if (tempSelectedOptions.length == 1) {
                for (let i = 0; i < this.selectedOptions.length; i++) {
                    if (i != this.selectedOptions.length - 1 && this.selectedOptions[i].value === tempSelectedOptions[0]) {
                        [this.selectedOptions[i], this.selectedOptions[i + 1]] = [this.selectedOptions[i + 1], this.selectedOptions[i]];
                        break;
                    }
                }
            }
        }
    }
    

    • handleSelectionForAvailable: This function is used to select/unselect value(s) under the available options section.
    • handleSelectionForSelected: This function is used to select/unselect value(s) selected options section.
    • handleLeftClick: This function is responsible to add the selected value(s) in the selected options section and remove values from available options section.
    • handleRightClick: This function is responsible to add the selected value(s) in the available options section and remove values from selected options section.
    • handleDownClick: This function is used to move values one step down in the selected options section.
    • handleUpClick: This function is used to move values one step up in the selected options section.

    customDualListBox.xml

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


    OUTPUT


    CONCLUSION

    By using the above code, We are able to make a custom dual list box with the same functionality as the standard Lightning-dual-listbox.


    If you have any questions you can reach out our Salesforce Consulting team here.

    Thursday, 12 May 2022

    Select the Right Report Type for New Reports Smoothly

    As with every Salesforce release, there are new features rolled out across the platform. With Spring ’22 there are some specific enhancements to Reports. Let’s take a look at it.

    Easily Find the Right Report Type for New Reports

    While creating a Report take the uncertainty out of selecting a report type. With the release of Spring ’22 enhanced report type selector, quickly access recently used report types and view the included fields and objects. Quickly identify which report types are standard and custom and hide those that you don't need.

    Let's look into the Report tab

    Start a new report on the Reports tab. In the Choose Report Type windows, you can still select report type categories on the left and search for report types by name in the search bar.

    But now there’s much more.

    Choose Report Type window

    If you want to create a report which is the same as one that you have created in the previous week, but you can’t remember what report type you used. No worry! scroll through the Recently Used list to find the type that you used and when you used it.

    Recently Used Reports

    To see the details of the Report Type, Click on the search report or recently used report list.

    Detail Panel

    In the detail panel following details display the Report

    1. The Report Created By.
    2. Report Created By Others in your org.
    3. The List of Objects used in the report type.
    4. Quick Lookup in the Fields used in Report.

    As Salesforce Classic, You can also hide the report type from the report type list. hidden report types do not appear in the search results and all the category-specific lists, and you can’t use them to create reports. You can see the hidden report type under the Hidden Report Type tab and available to see again if needed.

    Hidden Report Types

    Click Here to see the release notes on report type selector. 



    If you have any questions you can reach out our Salesforce Consulting team here.