Monday, July 19, 2021

Quick Action In LWC.


Today we are gonna talk about Quick Action in LWC.  Earlier we need to wrap up our LWC component inside the Aura component to use in Quick Action but after the Summer'21 Salesforce release, now we no longer need that. As of now, LWC is only supported in Record Detail Quick Action. First off, there are TWO different types of LWC Quick Actions – Screen Actions and Headless Actions.

How to setup Quick Action:

Setup-> Object Manager -> Object-> Buttons, Links, and Actions-> New Action








Screen Action:

 Basically, Screen actions are used when we need to open a modal window that we can use to display data or interact with data. Earlier we use the Aura component and inside Aura, we wrap/call our LWC component but now we don't need the Aura component anymore to call the LWC component in Quick Action.

To set up a Lightning web component as a quick action on a record page, define the metadata in <component>.js-meta.xml. Define a lightning__RecordAction target and specify actionType as ScreenAction for a screen action that opens in a window.

my-action.js-meta.xml

<?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__RecordAction</target>        
    </targets>
    <targetConfigs>
        <targetConfig targets="lightning__RecordAction">
            <actionType>ScreenAction</actionType>
        </targetConfig>
    </targetConfigs>
</LightningComponentBundle>

my-action.html

<template>
    <lightning-quick-action-panel header="Add Quick Contact">
       Modal Body

        <div slot="footer">
            <lightning-button variant="neutral" label="Close" 
                title="Close" onclick={closeModal}>
            </lightning-button>
            &nbsp;
            <lightning-button variant="brand" label="Save" 
                title="Save">
            </lightning-button>
        </div>
    </lightning-quick-action-panel>
</template>

There is a new base component introduce which is Lightning Quick Action Panel it's allow us to create a consistent experience for users.

This component allows you to:

  • Set the header attribute of the component to render the title in the modal header
  • Place the content of your action in the body
  • Use a slot to place content in the modal footer

my-action.js

import { LightningElement } from 'lwc';
import { CloseActionScreenEvent } from 'lightning/actions';


export default class QuickHeaderAction extends
    NavigationMixin(LightningElement) {

    closeModal() {     
        this.dispatchEvent(new CloseActionScreenEvent());
    }
}

Preview


Close Action Screen Event

We can close the modal when we are using ScreenAction by importing the new  CloseActionScreenEvent from 'lightning/actions'. When fired this will close the model window if the user needs to cancel or close the quick action.


Headless Action:

With the help of this action, we can run JavaScript directly from the click of a button through a Headless Lightning Web Component. As compared to ScreenAction we don't need the HTML file in your LWC.

In our .XML file we need to defined Action inside <actionType> tag for using headlessAction.

my-headless-action.js-meta.xml

<?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__RecordAction</target>        
    </targets>
    <targetConfigs>
        <targetConfig targets="lightning__RecordAction">
            <actionType>Action</actionType>
        </targetConfig>
    </targetConfigs>
</LightningComponentBundle>


A headless action can be invoked by creating an invoke() method that is exposed publicly with an @api decorator. Each time we clicked on the button this will call invoke() function every time. The component is inserted into the DOM right when the record page is rendered so you cannot rely on any of the standard lifecycle hooks for executing the action.

It is important to note that headless actions do not have the ability to prevent the user to double-click the action. The following code sample will show you how you can make the invoke() method asynchronous to prevent it from being called twice.

my-headless-action.js

import { LightningElementapiwire } from 'lwc';
import { ShowToastEvent } from 'lightning/platformShowToastEvent';
export default class HeadlessAsync extends LightningElement {
    isExecuting = false;    
    @api async invoke() {
        if (this.isExecuting) {
            return;
        }  
        this.isExecuting = true;
        this.dispatchEvent(new ShowToastEvent({
            title'Success',
            message'Your invoke function is called',
            variant'success'
        }));      
        await this.sleep(2000);
        this.isExecuting = false;    
    }  sleep(ms) {
        return new Promise((resolve=> setTimeout(resolvems));
    }  
}

Preview




I'll hope you enjoyed this blog and learned something new today. Please give us your suggestion in the comments section.


Saturday, July 10, 2021

Salesforce Summer ’21 Release Notes LWC Updates And New Features




The Lightning Component modern framework is a User Interface framework to develop dynamic web apps for mobile and desktop devices. In the latest Summer’21 release is packed with the newly added Lightning Component features!
Lightning Components: New and Changed Items
Build UI easily with these new and changed components.
New Components
These components are new and require API version 52.0 and later.
lightning-quick-action-panel

Builds quick action modals with the same style as the Salesforce Lightning Design System (SLDS) modal. With this component, you can customize screen actions and still have consistent UI across all actions. Use lightning-quick-action-panel with the lightning__RecordAction target to use your custom component as a quick action on a record page. For more information.

lightning-service-cloud-voice-toolkit-API

This component provides access to event listeners and methods for the Service Cloud Voice Toolkit API, enabling your component to listen to events that take place during phone calls with service agents.


Changed Lightning Web Components
These components have changed.

lightning-quick-action-panel

This attribute is new.

  • aria-haspopup—Indicates that the button has an interactive popup element. Valid values are true, false, menu, listbox, tree, grid, or dialog.
lightning-formatted-text

This attribute has changed.

  • value—When linkify is true, URLs specified without a protocol use the host domain's protocol. For example, if a host domain uses the https:// protocol when you specify value=” See www.example.com” the link renders as https://www.example.com.
lightning-formatted-URL

This attribute has changed.

  • href—URLs specified without a protocol use the host domain's protocol. For example, if a host domain uses the https:// protocol, when you specify href=”www.example.com” the link renders as https://www.example.com.
lightning-datatable

These attributes are new to provide a caption or description on the <table> element for assistive technologies. We recommend that you use one or the other, but not both.

  • aria-label—Labels the datatable for assistive technology. The attribute and its value are passed down to the rendered <table>  element.
  • aria-labelled by—Specifies the ID or list of IDs of the element or elements that contain visible descriptive text to caption or describe the table.
lightning-helptext

This attribute is new.

  • alternative-text—The assistive text for the button icon. This value defaults to "Help".
lightning-input-address

This attribute is new.

  • country-disabled—Specifies whether the country field is disabled so users can’t interact with it. This value defaults to false.
lightning-pill

This attribute has changed

  • href—URLs specified without a protocol use the host domain's protocol. For example, if a host domain uses the https:// protocol, when you specify href=”www.example.com” the link renders as https://www.example.com.

SEE ALSO: Component Library

Create Quick Actions with Lightning Web Components (Generally Available)
To save your users time and clicks, create a quick action that invokes a Lightning web component. On a record page, create a screen action that shows the component in a window, or create a headless action that executes with a click.

How to use: A Lightning web component as a quick action on a record page, define the metadata in fieldset><component> .js-meta.xml. Define a lightning__RecordAction target and specify actionType as ScreenAction for a screen action that opens in a window or Action for a headless action that executes when clicked. Here’s the configuration for a headless action.

 <?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__RecordAction</target>

        </targets>

        <targetConfigs>

          <targetConfig targets="lightning__RecordAction">

            <actionType>Action</actionType>

          </targetConfig>

        </targetConfigs>

      </LightningComponentBundle>

To use a headless action, add an exposed invoke() method to your component.

import { LightningElement, API } from "lwc";
    
declare default class HeadlessSimple extends LightningElement {
    @api invoke() {
         console.log("Hi, I'm an action."); 
    }
 }  

Note: LWC quick actions are currently supported only on record pages.

Create Styling Hooks for Lightning Web Components
To expose styling hooks for your custom components, use CSS custom properties. CSS custom properties also make code easier to read and update.

How to use: To define a CSS custom property in a component's style sheet, prefix the property with --. To insert the value of the property, use var()

:host {

    --important-color: red; 

}

 .important { 

    color: var(--important-color); 

}

CSS custom properties are inherited. Inherited properties pierce the shadow DOM. Some CSS properties, like color, are also inherited. Because CSS custom properties are inherited, a consumer can set their values at a higher level in the DOM tree and style your component. These CSS custom properties create styling hooks for two themes: light and dark. Pass the fallback value as an optional second parameter to var().

 
/* myComponent.css */
 .light {
     background-color: var(--light-theme-backgroud-color, lightcyan);
     color: var(--light-theme-text-color, darkblue);
 } 
.dark {
    background-color: var(--dark-theme-background-color, darkslategray); 
    color: var(--dark-theme-text-color, ghostwhite);
 }

A consumer can set values for the styling hooks to change the theme colors.

/* consumerComponent.css */
:host {
    --light-theme-backgroud-color: honeydew;
    --light-theme-text-color: darkgreen;
    --dark-theme-background-color: maroon;     
    --dark-theme-text-color: ivory; 

To experiment with this code in a playground, see lwc.dev.
At Last!!!

Monitor Lightning Component Changes in the Setup Audit Trail Use the audit trail to track when your users create, change, or delete a custom Lightning component. Audit history is especially useful when multiple developers work on components.

How to use: To view the audit history, from Setup, in the Quick Find box, enter View Setup Audit Trail, then select View Setup Audit Trail.

Note: Because of the structure of component bundles, more than one entry for the same change sometimes appears in the audit trail. But you can identify that the entries are for the same change because their timestamps are identical.

You can download release notes for PDF files.

I'll hope you like it.

Thanks to everyone 😁!!

Thursday, July 8, 2021

LWC Datatable with custom features

 Introduction


Lightning web components are custom HTML elements build using HTML and modern JavaScript.
Lightning Web Components uses core Web Components standards and provides only what’s necessary to perform well in browsers supported by Salesforce. Because it’s built on code that runs natively in browsers, Lightning Web Components is lightweight and delivers exceptional performance. Most of the code you write is standard JavaScript and HTML.

Advantages

  • Fast
  • Lightweight
  • Better browser compatibility
  • Better security
Data table

Today we gonna see the LWC data table with some custom features that Salesforce doesn't provide us i.e pagination and searching.

  • How to  implement LWC data table
<lightning-datatable
key-field="id"
data={dataToShow}
hide-checkbox-column
show-row-number-column
columns={columns}
onrowaction={handleRowAction}
default-sort-direction={defaultSortDirection}
sorted-direction={sortDirection}
sorted-by={sortedBy}
onsort={onHandleSort}></lightning-datatable>
  • Now we are going to create columns for the data table 
        get columns() {     return [{ label: 'First Name', fieldName: 'firstname', sortable: true, }, {}, { label: 'Last Name', fieldName: 'lastname', sortable: true, }, {}, { label: 'Phone', fieldName: 'Phone', type: 'phone', sortable: true, }, {}, { label: 'Date ', fieldName: 'createdDate', type: "date-local" }, { label: 'View Record', initialWidth: 100, type: "button-icon", typeAttributes: { iconName: 'utility:preview', name: 'View', title: 'View', disabled: false, variant: "bare" } }     ];         }

As you can see at last I used button recently Salesforce launch this new features in the LWC datatable where a user can add button on the row with onrowaction attribute of the LWC datatable. Now we have created columns for our LWC datatable.
  • Now we are defining some other properties which we used in our 'lightning:datatable' tag some properties are variables and some properties are functions, so right now we are defining only variables.
@track defaultSortDirection = 'asc';
@track sortDirection = 'asc'; @track sortedBy;

 Datatable Preview


Let's begin the fun part of datatable with pagination and other custom features

Pagination 
  • Define these variables in your code
    @track pageSizeDefault = '10';     @track recordsPerPage = [{ label: 10, value: '10' }, { label: 20, value: '20' }, { label: 50, value: '50' }, { label: 100, value: '100' }     ];     @track totalPages;     @track currentPage = 0;     @track startRecordIndex = 0;     @track endRecordIndex = 0;     @track dataToShow;
  •  After defining the variables you need to create this function.
setTablePagination() { if (this.data.length > 0) { let pageList = JSON.parse(JSON.stringify(this.data)); let newList = new Array(); this.currentPage = 0; this.startRecordIndex = 0; this.endRecordIndex = this.pageSizeDefault - 1; for (let i = 0; i < this.pageSizeDefault; i++) { if (this.data.length > i) { newList.push(JSON.parse(JSON.stringify(pageList[i]))); } } this.dataToShow = newList; console.log('records', this.dataToShow); this.totalPages = Math.ceil(this.data.length / this.pageSizeDefault); } }
 
Whenever your table data is ready you need to call this function. This function will divide your data. After doing this we need to add lwc: buttons and Combobox on the page so a user can control the pagination easily.

<div class="slds-grid slds-wrap slds-m-around_xx-small">
<div class="slds-col slds-grid slds-size_1-of-1">
<div class="slds-col slds-col slds-size_2-of-12">
<lightning-combobox name="Records Size" label="Records Per Page" value={pageSizeDefault} options={recordsPerPage} onchange={handlePageSize}>
value={pageSizeDefault} options={recordsPerPage} onchange={handlePageSize}></lightning-combobox>
</div>
<div class="slds-col slds-size_10-of-12 slds-p-top_large">
<div class="slds-clearfix">
<div class="slds-align_absolute-center">
<lightning-button label="" icon-name="utility:left" onclick={previousHandler} disabled={disabledPrevious} variant="base">
onclick={previousHandler} disabled={disabledPrevious}
variant="base"></lightning-button>
<span class="slds-m-left_x-small"> Showing page {getCurrentPage} from {totalPages} pages </span>
<lightning-button label="" icon-name="utility:right" class="slds-m-left_x-small" onclick={nextHandler} disabled={disabledNext} variant="base">
class="slds-m-left_x-small" onclick={nextHandler}
disabled={disabledNext} variant="base"></lightning-button>
</div>
</div>
</div>
</div>
</div>
 

You can change the pagination UI according to your requirement. Now we are going to handle previous and next button functionality as well as change Record page size.

    handlePageSize(event) {
this.pageSizeDefault = event.target.value;
this.totalPages =                         Math.ceil(this.tableDatalength / this.pageSizeDefault);
this.startRecordIndex = 0;
this.endRecordIndex = this.pageSizeDefault - 1;
this.currentPage = 0;
this.recordPageSize();
}

        //This function will handle and change the number of records showing on per page
recordPageSize() {
let newList = new Array();
for (let i = 0; i < this.pageSizeDefault; i++) {
if (this.data.length > i) {
newList.push(JSON.parse(JSON.stringify(this.data[i])));
}
}
this.dataToShow = newList;
}

previousHandler() {
let counter = 0;
let newList = new Array();
for (let i = this.startRecordIndex - this.pageSizeDefault;                         i < this.startRecordIndex; i++) {
if (i > -1) {
newList.push(JSON.parse(JSON.stringify(this.data[i])));
counter++;
} else {
this.startRecordIndex++;
}
}
this.dataToShow = newList;
this.startRecordIndex = this.startRecordIndex - counter;
this.endRecordIndex = this.endRecordIndex - counter;
this.currentPage--;
}

nextHandler() {
let counter = 0;
let newList = new Array();
let numberOfRec = parseInt(this.pageSizeDefault) +                              parseInt(this.endRecordIndex) + 1;
for (let i = this.endRecordIndex + 1; i < numberOfRec; i++) {
if (this.data.length > i) {
newList.push(JSON.parse(JSON.stringify(this.data[i])));
}
counter++;
}
this.startRecordIndex = this.startRecordIndex + counter;
this.endRecordIndex = this.endRecordIndex + counter;
this.currentPage++;
this.dataToShow = newList;
}

get getCurrentPage() {
return this.currentPage + 1;
}

    //This function will make previous button disabled if table is on the first page
get disabledPrevious() {
return this.startRecordIndex == 0 ? true : false;
}

    //This function will make next button disabled if table is on the last page
get disabledNext() {
return this.currentPage + 1 == this.totalPages ? true : false;
}
Congrats you have completed pagination on LWC:datatable.At last but not least we need to implement sorting as well. I know Salesforce already provided code for sorting the data of Datatable but that code is a little buggy. That's why I am doing this to share a code for sorting which runs seamlessly.

    onHandleSort(event) { console.log('event.detail', event.detail); const { fieldName: sortedBy, sortDirection } = event.detail; const cloneData = [...this.dataToShow]; console.log('cloneData', cloneData); cloneData.sort(this.sortBy(sortedBy, sortDirection === 'asc' ? 1 : -1)); console.log('cloneData', cloneData); this.dataToShow = cloneData; this.sortDirection = sortDirection; this.sortedBy = sortedBy;     }     sortBy(field, reverse, primer) { const key = primer ? function (x) { return primer(x[field]); } : function (x) { return x[field]; }; return function (a, b) { return a = key(a) ? key(a) : '', b = key(b) ? key(b) : '', reverse * ((a >         b) - (b > a)); };     }
    //This function will handle row action of our datatable
    handleRowAction(event) { const row = event.detail.row; console.log(row);     }

That's all from my side I'll hope you enjoyed this blog and learned something new today. If you facing any issue while implementing this pagination on the lwc:datatable. Please feel free to ask in the comments section or you can mail us on our Gmail id.

Thanks to everyone 😁!!