0% found this document useful (0 votes)
263 views72 pages

Endlwc

Uploaded by

xahewab432
Copyright
© © All Rights Reserved
We take content rights seriously. If you suspect this is your content, claim it here.
Available Formats
Download as PDF, TXT or read online on Scribd
0% found this document useful (0 votes)
263 views72 pages

Endlwc

Uploaded by

xahewab432
Copyright
© © All Rights Reserved
We take content rights seriously. If you suspect this is your content, claim it here.
Available Formats
Download as PDF, TXT or read online on Scribd
You are on page 1/ 72

Note:- Code is highlighted in a yellow background color.

15th August 2023

1. How to start using LWC?

● Install VS Code.
● Download and Install SFDX Cli.
● After Cli installation goto your installed path (i.e., C:\Program Files\sfdx\bin)
This will be the location where Cli is installed. Copy this path.
● Search for Environment variables in search tab of windows.
● Click Environments Variables -> Select Path on the upper User Variables and
click Edit. Now click new and paste your copied path.
● See the screenshot below.

● For confirmation open cmd and run it as administrator. Type “sfdx -v” in
command prompt and press enter.
● Open VS Code, Goto Extension and install “Salesforce Extension Pack”. See
the below screenshot.

● You can also follow this trailhead for setup of LWC.


2. Connect VS Code with Salesforce Org:-

Step 1:- Open Command Palette (Ctrl + Shift + P) in your VS Code and select option
“>SFDX: Create Project with Manifest”

Select “Standard” from the below options.

Enter Project Name and Save your folder.

Step 2:- The above step will create a folder in your local system. Now again Open
Command Palette and type “>SFDX: Authorize an Org”
Select “Project Default” from the below list (Depending upon which org you are
using)

You may enter an alias name or keep it blank.

After this you will be directed to the login page on the browser. Enter your credentials
and then your VS Code will be connected to your Org successfully.

Step 3:- After successful authorization open package.xml folder inside manifest
folder.
Right click on the file and click “SFDX: Retrieve Source in Manifest from Org”

After these steps you’ll see all your org data inside vs code.

Note:- If you are not able to see any command inside the command palette please
wait for a few minutes. The extensions take time to activate.

3. Introduction to LWC:-

● LWC is a new programming model to develop Salesforce lightning


components.
● It uses core web component standards and leverages custom elements,
templates, decorators, modules, shadow DOM, and other new language
constructs available in ECMAScript 7 and beyond.
● LWC are custom HTML elements built using HTML and modern JavaScript.
● LWC is available in Enterprise, Performance, Unlimited, and Developer
editions.
● LWC uses core Web Components standards and provides only what’s
necessary to perform well in browsers supported by Salesforce.
● Lightning Components previously could be developed using the aura
component framework. Now we have a new framework to develop the same
lightning components.

4. Why LWC?

In 2014, when the Lightning Components framework launched along with the Aura
programming model, web standards only offered a limited foundation for the full stack
that developers need to build large-scale web applications, i.e. a rendering engine,
standard elements, events, and a core language (ECMAScript 5).
The key elements like a component model, templates, modules, and shadow DOM
are all missing from the web standards.
● This means the web standards or the web stack in 2014 was not powerful
enough to help us create UI components.
● At the same time, many different frameworks came into the picture like
Angular, React, and Aura.
● All these frameworks came with these missing key elements that we needed
to create UI components.
● Now from 2014 onwards, there has been a lot of improvement in the web
stack or the native web browser engine.
● With the power of the latest web stack, LWC comes with many different
advantages over aura components as follows:

○ Better performance
○ Modern web standards
○ Compatible with Aura components
○ Faster loading sites
○ Better security, better testing, and better browser compatibility
○ Ease of development
5. LWC naming convention

● You can’t create a Lightning web component with same name as that of Aura
component in the same namespace.
● Must begin with a lowercase letter. While naming the LWC folder we have to
name it in camel case like “welcomeHello”. But when referring to the
component in markup,it maps to kebab case “<c-welcome-hello>”.
● Must contain only alphanumeric or underscore characters
● Must be unique in the namespace
● Should not contain whitespace
● Should not end with an underscore
● Should not contain two consecutive underscores
● Should not contain a hypen (dash)

6. LWC component/folder structure

● The main contents of an LWC are also HTML, JavaScript and XML
configuration file.
● An XML configuration file is included, which defines the metadata values for
the component.
● There is optional content like CSS.
● Take a look at the files in short:-

1. HTML
● Every UI component must have an HTML file with root tag
“template” so if you want to have any UI element like headings
or paragraph we need to place inside these template tags.
● Has a root tag <template> that contains your component’s
HTML
● When it renders, the <template> tag is replaced with
<namespace-component-name>

2. JavaScript:

● The JavaScript file defines the behaviour of HTML elements


present in HTML file.
● To import functionality declared in a module, use the import
statement.
● To allow other code to use functionality in a module, use the
export statement.
● LightningElement is a custom wrapper of the standard HTML
element and we extend it in the component and export.

3. Configuration:

● XML file that defines the metadata configuration values for the
component
● We set <targets> to deploy components for different pages like
the App page, Record page, etc.
● If isExposed is false, the component isn’t exposed to Lightning
App Builder or Experience Builder.
● To allow the component to be used in Lightning App Builder or
Experience Builder, set isExposed to true and define at least
one <target>, which is a type of Lightning page.
● Below are some of the possible values of target:-
○ lightning RecordPage
○ lightning AppPage
○ lightning HomePage
○ lightning Tab
○ lightning RecordAction
○ lightning Inbox
○ lightning UtilityBar
○ lightning FlowScreen
○ lightningSnapin ChatMessage
○ lightningSnapin Minimized
○ lightningSnapin PreChat
○ lightningSnapin ChatHeader
○ lightningCommunity__Page
○ lightningCommunity__Default
○ lightningCommunity__Page_Layout
○ lightningCommunity__Theme_Layout
4. CSS:

● To style a component.
● The style sheet is applied automatically.

7. Data binding in LWC

Data binding is a core concept in LWC that allows developers to establish a


relationship between a component's properties and the values displayed in its HTML
template. This relationship ensures that the component's properties are always in
sync with the values displayed in the template, and any changes made to one will be
automatically reflected in the other.

In LWC, there are two different data binding used -

A) Property binding: It is used to bind a component's property to a value in the


HTML template. To do this, we need to use the curly brace syntax ({}) to wrap
the property name in the template. For example, Suppose, there is a property
called "message" in the component, then we can bind it to an HTML element
like this:

<p>{message}</p>

Whenever the "message" property in the component is changed, the value


displayed in the HTML template will be automatically updated to reflect the
new value.

B) Event binding: This is used to bind an HTML element's event to a method in


the component. To do this, we need to use the on-syntax followed by the
event name and the name of the method to be called whenever the event is
triggered. For example, Suppose, we have a button in a component and we
want to call a method called "handleClick" when it is clicked, then we can bind
the event like this:

<lightning-button label="Neutral" title="Non-primary action"


onclick={handleClick} class="slds-m-left_x-small"></lightning-button>

Whenever the button is clicked, the "handleClick" method in the component


will be called

8. Hello World LWC Component


helloWorld.html

<template>
<lightning-card title="Hello World Component">
<div class="slds-p-left_medium">
Hello World.
</div>
</lightning-card>
</template>

helloWorld.js-meta.xml

<?xml version="1.0" encoding="UTF-8"?>


<LightningComponentBundle xmlns="http://soap.sforce.com/2006/04/metadata">
<apiVersion>57.0</apiVersion>
<isExposed>true</isExposed>
<targets>
<target>lightning__AppPage</target>
<target>lightning__RecordPage</target>
<target>lightning__HomePage</target>
</targets>
</LightningComponentBundle>
16th August 2023
1. Difference between var and let:-

The keywords let and var both declare new variables in JavaScript. The difference
between let and var is in the scope of the variables they create:

● Variables declared by let are only available inside the block where they’re
defined.
● Variables declared by var are available throughout the function in which
they’re declared.
● Also a variable declared with let cannot be declared again. With var it is
possible

1. var Example:-

a. Example 1:-

var i = 10;
{
console.log(i); //10
}
console.log(i); //10

Here variable is declared in the function and is accessible inside the


block as well as within the function.

b. Example 2:-

{
var i = 10;
console.log(i); //10
}
console.log(i); //10

Here variable is declared in the block and is accessible inside the


block as well as within the function.

c. Example 3:-

{
var i = 10;
console.log(i); //10
var i = 20;
}
console.log(i); //20

Here variable is declared in the block and again it is declared. This is


allowed for var variables.

2. let Example:-

a. Example 1:-

let i = 10;
{
console.log(i); //10
}
console.log(i); //10

Here let is declared outside the block hence it is accessible for whole
function as well as for the block.

b. Example 1:-

{
let i = 10;
console.log(i); //10
}
console.log(i); //Error

Here let is declared inside the block and it will not be accessible
outside the block.

c. Example 3:-

{
let i = 10;
console.log(i);
let i = 20;
}
console.log(i);

Here you will get error as i is already declared with let.

2. Lightning Input Example:-

Test Component:-
testComponent.html

<template>
<lightning-card title="Lightning Input Example">

<div class="slds-p-horizontal_x-small">
<lightning-input type="text"
label="First Name"
name="firstName"
placeholder="Enter First Name"
onchange={handleInput}>
</lightning-input>

<lightning-input type="text"
label="Last Name"
name="lastName"
placeholder="Enter Last Name"
onchange={handleInput}>
</lightning-input>
<br/>
<center>
<lightning-button variant="brand"
label="Submit"
title="Primary action"
onclick={handleButtonClick}
class="slds-m-left_x-small">
</lightning-button>
</center>
</div>
</lightning-card>
</template>

testComponent.js

import { LightningElement } from 'lwc';

export default class TestComponent extends LightningElement {

firstName;
lastName;

handleInput(event) {

if(event.target.name == 'firstName') {
this.firstName = event.target.value;
}

else if(event.target.name == 'lastName') {


this.lastName = event.target.value;
}
}

handleButtonClick() {
alert('First Name is : '+this.firstName);
alert('Last Name is : '+this.lastName);
}
}
17th August 2023
1. If else condition Example:-

The below component will take an age input from user and
will show whether you are eligible for voting or not.

Voting Component:-

votingComponent.html

<template>
<lightning-card title="Voting Component">

<div class="slds-p-horizontal_x-small">
<lightning-input type="number"
label="Enter your age"
placeholder="Enter Age.."
onchange={handleInput}>
</lightning-input>

<template lwc:if={eligible}>
You are eligible for voting.
</template>

<template lwc:elseif={notEligible}>
You are not eligible for voting.
</template>

<template lwc:else>
Please enter valid age.
</template>
</div>
</lightning-card>
</template>

votingComponent.js

import { LightningElement } from 'lwc';

export default class VotingComponent extends LightningElement {

age;
eligible = false;
notEligible = false;

handleInput(event) {
this.age = event.target.value;

if(this.age == '') {
this.eligible = false;
this.notEligible = false;
} else if(this.age < 18 && this.age > 0) {
this.eligible = false;
this.notEligible = true;
} else if(this.age >= 18 && this.age <= 100) {
this.eligible = true;
this.notEligible = false;
} else {
this.eligible = false;
this.notEligible = false;
}
}
}

2. Toast Message Example:-

● A Component can send a toast notification that pops up to alert users of


success, error, or warning.
● A Toast can also simply provide information.
● You can style toast and can configure the visibility of the toast.
● It can remain visible for three seconds until the user clicks to dismiss it, or a
combination of both.
● To display a toast notification in lightning experience or lightning communities,
import showToastEvent from the lightning/platformShowToastEvent module.

ShowToast Event Type Description


Parameter

title String The title of the toast displayed as a heading.

message String A string containing a message for the user.

messageData String[] or URL and label values that replace the


Object {index} placeholders in the message string.

variant String The theme and icon displayed in the toast. Valid
values are:
● Info – (Default) A gray box with an info
icon.

● Success – A green box with a checkmark


icon.

● Warning – A yellow box with a warning icon.

● Error – A red box with an error icon.

mode String Determines how persistent the toast is. Valid values
are:
● Dismissable – (Default) Remains visible until
the user clicks the close button or 3 seconds
has elapsed, whichever comes first.

● Pester – Remains visible for 3 seconds.

● Sticky – Remains visible until the user clicks


the close button.

Toast Component:-

toastComponent.html

<template>
<lightning-card title="Toast Component">

<div class="slds-p-horizontal_x-small">
<lightning-button variant="brand"
label="Info"
onclick={infoButton}
class="slds-m-left_x-small">
</lightning-button>
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;

<lightning-button variant="Success"
label="Success"
onclick={successButton}
class="slds-m-left_x-small">
</lightning-button>
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;

<lightning-button variant="destructive-text"
label="Warning"
onclick={warningButton}
class="slds-m-left_x-small">
</lightning-button>
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;

<lightning-button variant="destructive"
label="Error"
onclick={errorButton}
class="slds-m-left_x-small">
</lightning-button>
</div>
</lightning-card>
</template>

toastComponent.js

import { LightningElement } from 'lwc';


import { ShowToastEvent } from 'lightning/platformShowToastEvent';

export default class ToastComponent extends LightningElement {

infoButton() {
const event = new ShowToastEvent({
title: 'Info Toast Title',
message: 'Info Toast Message',
variant: 'info',
mode: 'Dismissable'
});
this.dispatchEvent(event);
}

successButton() {
const event = new ShowToastEvent({
title: 'Success Toast Title',
message: 'Success Toast Message',
variant: 'success',
mode: 'Pester'
});
this.dispatchEvent(event);
}

warningButton() {
const event = new ShowToastEvent({
title: 'Warning Toast Title',
message: 'Warning Toast Message',
variant: 'warning',
mode: 'Sticky'
});
this.dispatchEvent(event);
}
errorButton() {
const event = new ShowToastEvent({
title: 'Error Toast Title',
message: 'Error Toast Message',
variant: 'error',
});
this.dispatchEvent(event);
}
}

3. Calling Child Component from Parent Component

In the below example “parentComponent” is the name of Parent LWC Component


and “childComponent” is the name of Child LWC Component

Parent Component:-

parentComponent.html

<template>
<lightning-card>
Hello World from Parent Component

<!-- This below line will call the child component -->
<c-child-component></c-child-component>
</lightning-card>
</template>

parentComponent.js-meta.xml

<?xml version="1.0" encoding="UTF-8"?>


<LightningComponentBundle xmlns="http://soap.sforce.com/2006/04/metadata">
<apiVersion>57.0</apiVersion>
<isExposed>true</isExposed>
<targets>
<target>lightning__AppPage</target>
<target>lightning__RecordPage</target>
<target>lightning__HomePage</target>
</targets>
</LightningComponentBundle>

Child Component:-
childComponent.html

<template>
<lightning-card>
Hello World from Child Component
</lightning-card>
</template>

4. Decorators:-

In Lightning Web Components, we have three unique decorators that add


functionality to a function or property. Decorators dynamically alter or modify the
functionality.

A Decorator is a design pattern that allows adding behaviors to Javascript Objects.


Decorators which are part of ECMAScript are used to dynamically alter or modify the
functionality.

There are three type of Decorators in Lightning web components.

1. Api
2. Track
3. Wire

See the explanation of each decorators below:-

1. Api:-

● To make a property or function of javascript as public use api


decorator.
● By making any property or function as public any other component
can call or access them.
● The component which will call these functions or property will be
known as parent component or owner component.
● A Component is re-rendered when the value of a referenced public
property is modified or changed
● Let’s take a closer look using examples.

A) Public Property:-

Parent Component:-

parentComponent.html
<template>
<lightning-card title=”Parent Component”>

<c-child-component child-name=’Parent
Value’></c-child-component>
</lightning-card>
</template>

Child Component:-

childComponent.html

<template>
<lightning-card title=”Child Component”>
{childName}
</lightning-card>
</template>

childComponent.js

import { LightningElement, api} from 'lwc';

export default class ChildComponent extends LightningElement {

@api childName = ‘Child Value’;


}
18th August 2023

B) Public Function / Method:-

Parent Component:-

parentComponent.html

<template>
<lightning-card title="Parent Component">
<c-child-component child-name="Parent
Value"></c-child-component>

<lightning-button variant="brand"
title="Call Child Function"
label="Call Child Function"
onclick={parentFunction}
class="slds-m-left_x-small">
</lightning-button>
</lightning-card>
</template>

parentComponent.js

import { LightningElement } from 'lwc';

export default class ParentComponent extends LightningElement {

parentFunction() {
console.log('Parent Function Called');
this.template.querySelector('c-child-component').childFunction();
}
}

Child Component:-

childComponent.html

<template>
<lightning-card title="Child Component">
{childName}
</lightning-card>
</template>
childComponent.js

import { LightningElement, api } from 'lwc';

export default class ChildComponent extends LightningElement {

@api childName = 'Child Value';

@api
childFunction() {
console.log('Child Function Called');
this.childName = 'Value changed after parent called';
}
}

2. Track:-

● If any property value is changed and you want to show latest value in
the template use track.
● LWC component will rerender in the DOM.
● Private property you can say.
● After Salesforce Spring ’20, all the fields in a Lightning Web
Component are reactive. If a field is used in a template & value
changes, the component re-renders and displays a new value by
default

trackComponent.html

<template>
<lightning-card title="Parent Component">
<div class="slds-p-around_x-small">

First Name : {fullName.firstName}


<br/>
Last Name : {fullName.lastName}
<br/>

<lightning-input type="text"
label="First Name"
name="firstName"
placeholder="Enter First Name"
onchange={handleInput}>
</lightning-input>

<lightning-input type="text"
label="Last Name"
name="lastName"
placeholder="Enter Last Name"
onchange={handleInput}>
</lightning-input>

</div>
</lightning-card>
</template>

trackComponent.js

import { LightningElement, track } from 'lwc';

export default class TrackComponent extends LightningElement {

@track
fullName = {
firstName: "First Name",
lastName: "Last Name"
}

handleInput(event) {
console.log('Handle input is running');
if(event.target.name == 'firstName') {
this.fullName.firstName = event.target.value;
}

else if(event.target.name == 'lastName') {


this.fullName.lastName = event.target.value;
}

console.log('fullName property value :


'+JSON.stringify(this.fullName));
}
}

3. Wire:-

● To read Salesforce data.


● Wire are of reactive nature i.e., If any Salesforce data is updated we
will get the updated data in LWC.
● @AuraEnabled(cacheable=true) is important.
● How to make a method available for LWC. See the below
considerations:-
○ If a method is getting called from LWC annotate it with
@AuraEnabled.
○ If it is getting called using wire decorator annotate it with
@AuraEnabled(cacheable=true)
○ Here cacheable=true enable client side caching. So marking a
method as cacheable improves our component’s performance.
Because it can quickly show cached data from client-side
storage without waiting for a server trip.
○ But once we have used cacheable we cannot use DML in that.

● Syntax of calling Apex Method from LWC using wire and assigning
result to a JS function:-
○ Inside js class of LWC at the top write the below syntax:-
■ Import uniqueName from
‘@salesforce/apex/ApexClassName.ApexMethodName
’;

○ To call using wire write below syntax:-


■ @wire(uniqueName, {param1: value1, param2:
value2})
wiredJsFunction({data, error}) {

if(data) {
//This will run if Apex has no error
}

Else if(error) {
//This will run if Apex has any error.
}
}

○ In the above part, passing parameters is optional part, you can


pass parameters if your apex method is accepting any
parameters.
○ “data” will have the returned value from apex.
○ “error” will contain the run time error msg from apex.

● Syntax of calling Apex Method from LWC using wire and assigning
result to a Property:-
○ Inside js class of LWC at the top write the below syntax:-
■ Import uniqueName from
‘@salesforce/apex/ApexClassName.ApexMethodName
’;\

○ To call using wire write below syntax:-


■ @wire(uniqueName, {param1: value1, param2:
value2})
fetchedData

○ “fetchedData.data” will have the returned value from apex.


○ “fetchedData.error” will contain the run time error msg from
apex.

Apex Class for the below wire example:-

LWC_ControllerClass.apxc

public class LWC_ControllerClass {

@AuraEnabled(cacheable=true)
public static List<Account> accRecords() {

System.debug('Method is called');
return [SELECT Id, Name FROM Account LIMIT 10];
}
}

A) Assigning wire result to JS Function:-

wireComponent.html

<template>
<lightning-card title="Wire Decorator Component">
<template if:true={fetchedAccounts}>
<table>
<tr>
<th>Id</th>
<th>Name</th>
</tr>

<template for:each={fetchedAccounts} for:item="acc">


<tr key={acc.Id}>
<td>{acc.Id}</td>
<td>{acc.Name}</td>
</tr>
</template>
</table>
</template>
</lightning-card>
</template>

wireComponent.js
import { LightningElement, track, wire } from 'lwc';
import accountRecords from
'@salesforce/apex/LWC_ControllerClass.accRecords';

export default class WireComponent extends LightningElement {

@track
fetchedAccounts;

@wire(accountRecords)
wiredAccounts({error, data}) {

if(data) {
this.fetchedAccounts = data;
} else if(error) {
console.log(error);
}
}
}

B) Assigning wire result to a property:-

wireComponent.html

<template>
<lightning-card title="Wire Decorator Component">
<template if:true={fetchedAccounts.data}>
<table>
<tr>
<th>Id</th>
<th>Name</th>
</tr>

<template for:each={fetchedAccounts.data} for:item="acc">


<tr key={acc.Id}>
<td>{acc.Id}</td>
<td>{acc.Name}</td>
</tr>
</template>
</table>
</template>

<template if:true={fetchedAccounts.error}>
Apex Error
</template>
</lightning-card>
</template>

wireComponent.js

import { LightningElement, wire } from 'lwc';


import accountRecords from
'@salesforce/apex/LWC_ControllerClass.accRecords';

export default class WireComponent extends LightningElement {

@wire(accountRecords)
fetchedAccounts;
}
19th August 2023
1. Imperative Apex Calling:-

● Consider the case when you do not want an apex method to be called when
the component is loaded.
● In order to invoke the apex method on click of a button, or in response to a
certain logic, we could invoke the apex method in an imperative fashion.
● Consider the above example apex class for this as well.

imperativeComponent.html

<template>
<lightning-card title="Imperative Component">

<lightning-button variant="brand"
label="Show Records"
onclick={handleClick}
class="slds-m-left_x-small">
</lightning-button>

<template if:true={showTable}>
<table>
<tr>
<th>Id</th>
<th>Name</th>
</tr>

<template for:each={fetchedAccounts} for:item="acc">


<tr key={acc.Id}>
<td>{acc.Id}</td>
<td>{acc.Name}</td>
</tr>
</template>
</table>
</template>
</lightning-card>
</template>

imperativeComponent.js

import { LightningElement, track } from 'lwc';


import accountRecords from
'@salesforce/apex/LWC_ControllerClass.accRecords';
export default class ImperativeComponent extends LightningElement {

showTable = false;
@track fetchedAccounts;

handleClick() {

accountRecords().then(result => {
this.showTable = true;
this.fetchedAccounts = result;
}).catch(error => {
console.log('Error occured : '+error);
})
}
}

● Below is the same html code for the above example using SLDS Table

<template>
<lightning-card title="Imperative Component">

<lightning-button variant="brand"
label="Show Records"
onclick={handleClick}
class="slds-m-left_x-small">
</lightning-button>

<template if:true={showTable}>
<table class="slds-table slds-table_cell-buffer slds-no-row-hover
slds-table_bordered" aria-label="Example table of Opportunities with no row
hovers">
<thead>
<tr class="slds-line-height_reset">
<th class="" scope="col">
<div class="slds-truncate" title="Account Id">Account Id</div>
</th>
<th class="" scope="col">
<div class="slds-truncate" title="Account Name">Account
Name</div>
</th>
</tr>
</thead>
<tbody>

<template for:each={fetchedAccounts} for:item="acc">


<tr class="slds-hint-parent" key={acc.Id}>
<td data-label="Account Id">
<div class="slds-truncate">{acc.Id}</div>
</td>
<td data-label="Account Name">
<div class="slds-truncate">{acc.Name}</div>
</td>
</tr>
</template>
</tbody>
</table>
</template>
</lightning-card>
</template>

2. Show records using lightning-input:-

LWC_ControllerClass.apxc

public class LWC_ControllerClass {

@AuraEnabled(cacheable=true)
public static List<Account> accRecords(String inputName) {

String accName = '%'+inputName+'%';


System.debug('Method is called');
return [SELECT Id, Name FROM Account WHERE Name like
:accName];
}
}

imperativeComponent.html

<template>
<lightning-card title="Imperative Component">

<lightning-input type="text"
label="Enter some text"
onchange={handleInput}>
</lightning-input>

<template if:true={showTable}>
<table class="slds-table slds-table_cell-buffer slds-no-row-hover
slds-table_bordered" aria-label="Example table of Opportunities with no row
hovers">
<thead>
<tr class="slds-line-height_reset">
<th class="" scope="col">
<div class="slds-truncate" title="Account Id">Account Id</div>
</th>
<th class="" scope="col">
<div class="slds-truncate" title="Account Name">Account
Name</div>
</th>
</tr>
</thead>
<tbody>

<template for:each={fetchedAccounts} for:item="acc">


<tr class="slds-hint-parent" key={acc.Id}>
<td data-label="Account Id">
<div class="slds-truncate">{acc.Id}</div>
</td>
<td data-label="Account Name">
<div class="slds-truncate">{acc.Name}</div>
</td>
</tr>
</template>
</tbody>
</table>
</template>
</lightning-card>
</template>

imperativeComponent.js

import { LightningElement, track } from 'lwc';


import accountRecords from
'@salesforce/apex/LWC_ControllerClass.accRecords';

export default class ImperativeComponent extends LightningElement {

showTable = false;
@track fetchedAccounts;

handleInput(event) {

accountRecords({inputName: event.target.value}).then(result => {


this.showTable = true;
this.fetchedAccounts = result;
}).catch(error => {
console.log('Error occurred : '+error);
})
}
}

3. Calling Parent Component from Child Component

● Custom Event can be used to communicate from child component to parent


component.
● CustomEvent() constructor can be used to create a custom event.
● Custom Event Name and properties should be passed into the constructor.
● The dispatchEvent() method is used to dispatch an event, and the code looks
like this:
this.dispatchEvent(new customEvent(eventName, props);
● The event name which you have given you need to append on before that
name in Parent Component tag from which Child component is getting called.
● See the below example to get a clear idea.

Parent Component:-

parentComponent.html

<template>
<lightning-card title="Parent Component">

Count Value is : {count}


<c-child-component onadd={addMethod}
onsubtract={subtractMethod}>

</c-child-component>
</lightning-card>
</template>

parentComponent.js

import { LightningElement } from 'lwc';

export default class ParentComponent extends LightningElement {

count = 0;

addMethod(event) {
this.count = this.count + event.detail;
}
subtractMethod(event) {
this.count = this.count - event.detail;
}
}

Child Component:-

childComponent.html

<template>
<lightning-card title="Child Component">

<lightning-input type="number"
label="Enter the value"
onchange={handleChange}>
</lightning-input>

<lightning-button variant="brand-outline"
label="Add"
onclick={handleAdd}
class="slds-m-left_x-small">
</lightning-button>

<lightning-button variant="destructive-text"
label="Subtract"
onclick={handleSubtract}
class="slds-m-left_x-small">
</lightning-button>

</lightning-card>
</template>

childComponent.js

import { LightningElement } from 'lwc';

export default class ChildComponent extends LightningElement {

inputValue;

handleChange(event) {
this.inputValue = parseInt(event.target.value);
}

handleAdd() {
const myEvent = new CustomEvent('add', {
detail: this.inputValue
});
this.dispatchEvent(myEvent);
}

handleSubtract() {
const myEvent = new CustomEvent('subtract', {
detail: this.inputValue
});
this.dispatchEvent(myEvent);
}
}
20th August 2023

1. Life Cycle of LWC:-

A) Constructor:-
● Parent to Child.
● Constructor Life Cycle Hook is the one that gets invoked when
component is loaded.
● super() is mandatory.
● We can set the value of properties in constructor.
● We can't access HTML elements inside constructor. (Explaind later)
○ Example:-
■ this.template.queryselector(‘lightning-input’).label; is not
accessible.
● We can call apex method.
● We can't create custom events in constructor.
● We can use navigation service.
● We can make a call to uiRecordApi inside the constructor.
● Cannot access child components as flow is from parent to child. Child
components are not inserted yet.
● Refer the below link for more information
https://salesforcediaries.com/2019/12/12/constructor-in-lightning-web-
component/#:~:text=Constructor%20in%20Lightning%20Web%20Co
mponent%20is%20part%20of%20the%20lifecycle,flows%20from%20
parent%20to%20child.

B) ConnectedCallback:-

● Parent to Child.
● Cannot access child component since they are not inserted yet.
● This method is called when LWC is inserted into DOM.
● Invoked after constructor is fired.
● We can write logic on component load like assigning values to
properties, dispatching events, getting data from Salesforce.
● Refer the below link for more information
https://salesforcediaries.com/2019/12/13/connectedcallback-in-lightnin
g-web-component/

C) RenderedCallback:-

● Child to Parent.
● renderedCallback() method of child gets fired first (if any) then parent.
● You can set properties in renderedCallback, but best practices is to
avoid using that.
● We can call apex method.
● We can access HTML elements.
● We can use navigation service.
● We can make a call to uiRecordApi.
● Gets called multiple times.
● Refer the below link for more information
https://salesforcediaries.com/2020/01/01/renderedcallback-in-lightning
-web-component/

Let’s take a look at the examples of these 3 lifecycle first:-

Parent Component:-

parentComponent.html

<template>
<lightning-card>
Parent Component
<c-child-component></c-child-component>
</lightning-card>
</template>

parentComponent.js

import { LightningElement } from 'lwc';

export default class ParentComponent extends LightningElement {

constructor() {
super();
console.log('Inside parent constructor');
}

connectedCallback() {
console.log('Inside parent connectedCallback');
}

renderedCallback() {
console.log('Inside parent renderedCallback');
}
}

Child Component:-

childComponent.html

<template>
<lightning-card>
Child Component
</lightning-card>
</template>

childComponent.js

import { LightningElement, api} from 'lwc';

export default class ChildComponent extends LightningElement {

constructor() {
super();
console.log('Inside child constructor');
}

connectedCallback() {
console.log('Inside child connectedCallback');
}

renderedCallback() {
console.log('Inside child renderedCallback');
}
}

Note:- In the above example parent constructor and connectedCallback will


run first then child constructor, connectedCallback, renderedCallback will run and at
the last parent renderedCallback will be executed.

➔ How to access HTML Elements inside Javascript

testComponent.html

<template>
<lightning-card>
<lightning-button label="First Button"
data-id="firstButton"></lightning-button>
<lightning-button label="Second Button"
data-id="secondButton"></lightning-button>
</lightning-card>
</template>

testComponent.js

import { LightningElement } from 'lwc';

export default class TestComponent extends LightningElement {


constructor() {
super();
console.log('Inside parent constructor');
}

connectedCallback() {
console.log('Inside parent connectedCallback');
}

renderedCallback() {
console.log('Inside parent
renderedCallback'+this.template.querySelector('[data-id="secondButton"]').lab
el);
}
}

Note:- Here we have used data-id for unique identification.

➔ Why we cannot set properties inside renderedCallback?

If any property displayed on HTML if its value is changed then the component
is rendered. Let’s see the below example.

testComponent.html

<template>
<lightning-card title="Parent Component">
{textMessage}

<lightning-button variant="brand"
label="Click Here"
onclick={handleClick}
class="slds-m-left_x-small">
</lightning-button>
</lightning-card>
</template>

testComponent.js

import { LightningElement } from 'lwc';

export default class TestComponent extends LightningElement {


textMessage = 'Default Value';

renderedCallback() {
this.textMessage = 'Changed from Rendered Callback';
}

handleClick() {
this.textMessage = 'Changed from Method';
}
}

Note:- After every button click we will change textMessage property and as
this property is used in HTML the component will render and renderedCallback will
again reset the value to ‘Changed from Rendered Callback’

D) Render:-

● Parent to Child.
● Call this method to update the UI.
● It may be called before or after.
● After rendering the parent it jumps to the child constructor.
● This is mainly used to conditionally change the template.
● You need to import your template into your JavaScript file
● The call to render() must return the imported variable (shown in the
example below)
● Refer the below link for more information
https://salesforcediaries.com/2019/09/29/conditional-rendering-of-diffe
rent-html-file-in-lightning-web-component/

primaryComponent.html

<template>
<lightning-card title="Primary Component">
This is Primary HTML
<lightning-button variant="brand"
label="Show Secondary Template"
onclick={changeTemplates}
class="slds-m-left_x-small">
</lightning-button>
</lightning-card>
</template>

primaryComponent.js
import { LightningElement } from 'lwc';
import primaryComponent from './primaryComponent.html';
import secondaryComponent from './secondaryComponent.html';

export default class PrimaryComponent extends LightningElement {

changeFile = false;

changeTemplates() {
this.changeFile = !this.changeFile;
}

render() {

if(this.changeFile) {
return secondaryComponent;
} else {
return primaryComponent;
}
}
}

secondaryComponent.html

<template>
<lightning-card title="Secondary Component">
This is Secondary HTML

<lightning-button variant="brand"
label="Show Primary Template"
onclick={changeTemplates}
class="slds-m-left_x-small">
</lightning-button>
</lightning-card>
</template>
21st August 2023
E) DisconnectedCallback:-

● Parent to Child.
● DisconnectedCallback() Invoked when a component is removed from
DOM.
● For ex is can be used for removing event listeners that are created on
connectedCallback().
● Refer the below link for more information
https://www.salesforcepoint.com/2020/10/disconnectedCallback-lwc-e
xample.html

Parent Component:-

parentComponent.html

<template>
<lightning-card title="Parent Component">

<lightning-button variant="brand"
label="Click Here"
onclick={toggleChild}
class="slds-m-left_x-small">
</lightning-button>

<template if:true={showChild}>
<c-child-component></c-child-component>
</template>
</lightning-card>
</template>

parentComponent.js

import { LightningElement } from 'lwc';

export default class ParentComponent extends LightningElement {

showChild = false;

disconnectedCallback() {
console.log('Inside parent disconnected callback');
}
toggleChild() {
this.showChild = !this.showChild;
}
}

Child Component:-

childComponent.html

<template>
<lightning-card title="Child Component">
Child Component
</lightning-card>
</template>

childComponent.js

import { LightningElement } from 'lwc';

export default class CLWC extends LightningElement {

disconnectedCallback() {
console.log('Inside child disconnected callback');
}
}

F) ErrorCallback:-

● ErrorCallback() Invoked when the component throws error in one of


the lifecycle hooks (instantiating the component, connecting or
rendering).
● It Captures errors that may happen in all the child components
lifecycle hooks.
● Error and Stack are the two arguments.error is javascript native error
object whereas stack is a string.
● Error in parent shows in UI no boundary component for it. This means
if there is an error in the child, the parent handles the error, but if there
is an error in the parent, it is shown in the UI.
● This method works like a Javascript catch() block for catching errors

Parent Component:-

parentComponent.html
<template>
<lightning-card title="Parent Component">
<c-child-component></c-child-component>
</lightning-card>
</template>

parentComponent.js

import { LightningElement } from 'lwc';

export default class ParentComponent extends LightningElement {

errorCallback(error, stack) {
console.log('Inside error callback');
console.log('Error : '+error);
console.log('Stack : '+stack);
}
}

Child Component:-

childComponent.html

<template>
<lightning-card title="Child Component">
<lightning-input type="number"
label="Enter percentage"
onchange={handlePercent}>
</lightning-input>
</lightning-card>
</template>

childComponent.js

import { LightningElement } from 'lwc';

export default class CLWC extends LightningElement {

handlePercent(event) {
if(parseInt(event.target.value) > 100 ||
parseInt(event.target.value) < 0) {
throw new Error('Invalid percentage');
}
}
}

1. Simplifying LWC Lifecycle Hooks 😎


The Most Important LWC Interview Question for Salesforce Developers. 💪
Just like how we follow a certain routine every day, LWC components also have a

😝
special routine called "lifecycle." Let's see what happens at each stage of this routine
with some fun examples.

★ 🚀 Constructor (Getting Ready)


Imagine you are building a robot using Lego blocks. The constructor is like the first
step when you gather all the pieces you need. It helps you get ready by organizing
the parts and setting up any special features. For example, you would give your robot
a name, attach wheels, and add colorful stickers.

The first function that is invoked when a component is formed is constructor(). The
state of the component is initialised, and event listeners are set up.

★ 🚀 ConnectedCallback (Power On)


Now that your robot is assembled, it's time to bring it to life! The connectedCallback
is like turning on the power switch. Once you do that, your robot springs into action. It
starts moving, talking, and interacting with you. It can even detect obstacles and
avoid them while moving around!

When a component is added to the DOM, this function is called. It is used to carry out
operations that need access to the DOM.

★ 🚀 RenderedCallback (Appearance Matters)


Your robot is up and running, but it needs to look good too! The renderedCallback is
like your robot getting dressed up and ready for a party. You can change its
appearance by giving it a different color, adding cool accessories, or even making it
dance to your favorite music.

RenderedCallback(), is invoked each time the template of a component is rendered.


It is used to carry out operations that need access to the DOM, like modifying the
component's CSS styling or changing its state.

★ 🚀 DisconnectedCallback (Bye-bye Robot)


After a fun day of playing with your robot, it's time to put it away. The
disconnectedCallback is like saying goodbye and turning off the robot. You make
sure it goes back to its box, remove any batteries, and store it safely until the next
adventure.
DisconnectedCallback() is a method that is invoked when a component is deleted
from the DOM. Any resources that were created in the connectedCallback() method
are cleaned up using this technique.

★ 🚀 ErrorCallback (Oops, Something Went Wrong)


Sometimes, even robots can have a bad day. The errorCallback is like your robot
encountering a problem while performing a task. It might get stuck or confused. But
don't worry! It will display a friendly message asking for help, and you can fix the
issue together.

When there is a rendering fault with the component or one with a child component,
the method ErrorCallback() is invoked. Error handling and user error message
display are done with it.

2. Lightning Data Service (LDS):-

● Lightning Data Service is the preferred (and easiest) way to work with
Salesforce data.
● JavaScript is used to connect with Salesforce data.
● If there are more than 1 component on a lightning page and consider both are
showing/working on same record then LDS will load that record only once and
it will be cached and shared to the components on the same page.
● We can use LDS in our Lightning components to perform various CRUD
operations like create, read, update or delete a record without the use of any
Apex code.
● This automatically gives us enhanced performance and UI consistency.

● Below are the advantages of LDS:-


○ Improved performance.
○ Caches data on the client-side, so server overhead is reduced.
○ Data is consistent between all components that are using LDS.
○ If data is changed at one place on the page, it will be refreshed in all
other components on the page.
○ It does not cost against API usage calls.
○ Automatically refreshes the data in the cache when it is outdated.
○ It honors the CRUD permission for the records and objects.
○ This reduced complexity means that you don't have to spend as much
time on performance and quality testing.

● Below are the 3 base lightning components build on Lightning Data Service:
○ lightning-record-form: A form with standard lightning UI to create,
view or edit a record
○ lightning-record-edit-form: A form to create record with specified
fields or update fields in an existing record
○ lightning-record-view-form: A form to display specific fields data of a
record in read-only mode
A) lightning-record-form:-

● Use the lightning-record-form component to quickly create forms to


add, view, or update a record.
● Using this component to create record forms is easier than building
forms manually with lightning-record-edit-form or
lightning-record-view-form.
● Switches between view and edit modes automatically when the user
begins editing a field in a view form.
● Provides Cancel and Save buttons automatically in edit forms.
● Loads all fields in the object’s compact or full layout, or only the fields
you specify.
● This component doesn't support all Salesforce standard objects. For
example, the Event and Task objects are not supported. This limitation
also applies to a record that references a field that belongs to an
unsupported object.

● Mode values are:-


○ edit
○ view
○ readonly

● layout-type values are:-


○ Full
○ Compact (Compact Layout)

● Example:-

ldsComponent.html

<template>
<lightning-card title="Record Form Account Details">
<lightning-record-form
record-id = {recordId}
object-api-name = {objName}
fields = {selectedFields}
mode = "edit">
</lightning-record-form>

<!-- This will show all fields


<lightning-record-form
record-id = {recordId}
object-api-name = {objName}
layout-type="Full"
mode = "edit">
</lightning-record-form>
-->

</lightning-card>
</template>

ldsComponent.js

import { LightningElement } from 'lwc';


import ACCOUNT_NAME from '@salesforce/schema/Account.Name';
import ACCOUNT_TYPE from '@salesforce/schema/Account.Type';

export default class LdsComponent extends LightningElement {

selectedFields = [ACCOUNT_NAME, ACCOUNT_TYPE];


recordId = '0015g00001GgrKmAAJ';
objName = 'Account';
}

● Example to create record:-

ldsComponent.html

<template>
<lightning-card title="Record Form Account Details">
<lightning-record-form
fields = {selectedFields}
object-api-name = {objName}
onsuccess={handleSuccess}>
</lightning-record-form>
</lightning-card>
</template>

ldsComponent.js

import { LightningElement } from 'lwc';


import ACCOUNT_NAME from '@salesforce/schema/Account.Name';
import ACCOUNT_TYPE from '@salesforce/schema/Account.Type';
import { ShowToastEvent } from 'lightning/platformShowToastEvent';

export default class LdsComponent extends LightningElement {


selectedFields = [ACCOUNT_NAME, ACCOUNT_TYPE,
ACCOUNT_OWNER];
objName = 'Account';

handleSuccess(event) {
const evt = new ShowToastEvent({
title: 'Account created',
message: 'Record ID: ' + event.detail.id,
variant: 'success',
});
this.dispatchEvent(evt);
}
}

B) lightning-record-edit-form:-

● A lightning-record-edit-form component is a wrapper component that


accepts a record ID and object name.
● It is used to add a Salesforce record or update fields in an existing
record.
● The component displays fields with their labels and the current values
and enables you to edit their values.
● The lightning-input-field component is used inside the
lightning-record-edit-form to create editable fields.
● The lightning-output-field component and other display components
such as lightning-formatted-name can be used to display read-only
information in your form.
● lightning-record-edit-form implements Lightning Data Service.
● It doesn’t require additional Apex controllers to create or update
records.
● Using lightning-record-edit-form to create or update records with Apex
controllers can lead to unexpected behaviors.
● This component also takes care of field-level security and sharing for
you, so users see only the data they have access to.
● Features of lightning-record-edit-form:-
○ Editing a record’s specified fields, given the record ID.
○ Creating a record using specified fields.
○ Customizing the form layout
○ Custom rendering of record data

1) Editing a Record:-

● To enable record editing, pass in the ID of the record and the


corresponding object API name to be edited.
● Specify the fields you want to include in the record edit layout
using lightning-input-field.
● Include a lightning-button component with type=”submit” to
automatically save any changes in the input fields when the
button is clicked.

ldsComponent.html

<template>
<lightning-card title="Contact Edit Form Component">

<lightning-record-edit-form record-id={recordId}
object-api-name="Contact"
onsuccess={handleSuccess}
onsubmit ={handleSubmit}>

<lightning-output-field field-name="AccountId">
</lightning-output-field>

<lightning-input-field field-name="FirstName">
</lightning-input-field>

<lightning-input-field field-name="LastName">
</lightning-input-field>

<lightning-input-field field-name="Email">
</lightning-input-field>

<lightning-button class="slds-m-top_small"
variant="brand"
type="submit"
name="update"
label="Update">
</lightning-button>
</lightning-record-edit-form>
</lightning-card>
</template>

ldsComponent.js

import { LightningElement } from 'lwc';

export default class LdsComponent extends LightningElement


{
recordId = '0035g00000xpMH0AAM';

handleSubmit(event) {

console.log('onsubmit event recordEditForm');


}

handleSuccess(event) {

console.log('onsuccess event
recordEditForm'+event.detail.id);
}
}

Note:- In the above example onsubmit and onsuccess


attributes are optional.
22nd August 2023
C) lightning-record-view-form:-

● A lightning-record-view-form component is a wrapper component that


accepts a record ID and is used to display one or more fields and
labels associated with that record using lightning-output-field.
● lightning-record-view-form requires a record ID to display the fields on
the record.
● It doesn’t require additional Apex controllers or Lightning Data Service
to display record data.
● This component also takes care of field-level security and sharing for
you.
● Users will see data only if they have access to view specific field and
record.

ldsComponent.html

<template>
<lightning-card title="Contact Edit Form Component">

<lightning-record-view-form record-id={recordId}
object-api-name="Account">

<lightning-output-field
field-name="Name"></lightning-output-field>

<lightning-output-field
field-name="Website"></lightning-output-field>

<lightning-output-field
field-name="Industry"></lightning-output-field>

<lightning-output-field
field-name="AnnualRevenue"></lightning-output-field>

</lightning-record-view-form>
</lightning-card>
</template>

ldsComponent.js

import { LightningElement } from 'lwc';


export default class LdsComponent extends LightningElement {

recordId = '0015g00000n9m4uAAA';
}

1. Lightning Data Table:-

● lightning-datatable component displays tabular data for list of records.


● lightning-datatable component supports inline editing, which enables you to
update a field value without navigating to the record. We cab display each
column based on the data type.
● Essential attibutes of lightining-datatable:-

○ key-field: To specify a unique identifier for each row of the table. It'll
be a string specifying the key column in the data that we need to use
to identify each row.

○ data: Information to be displayed in the datatable. The value passed


to this attribute should be a javascript array.

○ columns: Information about columns of the datatable. This include


column name and other metadata associated with it like: type,
fieldName, icon details etc. The value passed to this attribute should
be a javascript array as well.

● Simple Lightning Datatable example:-

lightningDatatableComponent.html

<template>
<lightning-card title="Lightning Data Table">

<lightning-datatable data={fetchedAccounts}
columns={columns}
key-field="Id" >

</lightning-datatable>
</lightning-card>
</template>

lightningDatatableComponent.js

import { LightningElement, wire } from 'lwc';


import accountRecords from
'@salesforce/apex/ControllerClass.accountRecords';

export default class LightningDatatableComponent extends LightningElement


{

fetchedAccounts;

columns = [{
label: 'Account name',
fieldName: 'Name',
type: 'text'
},
{
label: 'Type',
fieldName: 'Type',
type: 'text'
},
{
label: 'Annual Revenue',
fieldName: 'AnnualRevenue',
type: 'Currency'
},
{
label: 'Phone',
fieldName: 'Phone',
type: 'phone'
},
{
label: 'Website',
fieldName: 'Website',
type: 'url'
},
{
label: 'Rating',
fieldName: 'Rating',
type: 'text'
}
];

@wire(accountRecords)
wiredAccounts({ error, data }) {
if (data) {
this.fetchedAccounts = data;
} else if (error) {
console.log(error);
}
}
}

Apex Method:-

public class ControllerClass {

@AuraEnabled(cacheable=true)
public static List<Account> accountRecords() {
return [SELECT Id, Name, Rating, Website, Type, AnnualRevenue,
Phone FROM Account];
}
}

● Lightning Datatable with inline editing example:-

lightningDatatableComponent.html

<template>
<lightning-card title="Lightning Data Table">
<lightning-datatable data={fetchedAccounts}
columns={columns}
key-field="Id"
hide-checkbox-column
draft-values={draftValues}
onsave={handleSave}>
</lightning-datatable>
</lightning-card>
</template>

lightningDatatableComponent.js

import { LightningElement, wire } from 'lwc';


import accountRecords from
'@salesforce/apex/ControllerClass.accountRecords';
import updateAccounts from
'@salesforce/apex/ControllerClass.updateAccounts';
import { ShowToastEvent } from 'lightning/platformShowToastEvent';

export default class LightningDatatableComponent extends LightningElement


{

fetchedAccounts;
draftValues = [];

columns = [{
label: 'Account name',
fieldName: 'Name',
type: 'text',
editable: true
},
{
label: 'Type',
fieldName: 'Type',
type: 'text'
},
{
label: 'Annual Revenue',
fieldName: 'AnnualRevenue',
type: 'Currency'
},
{
label: 'Phone',
fieldName: 'Phone',
type: 'phone'
},
{
label: 'Website',
fieldName: 'Website',
type: 'url'
},
{
label: 'Rating',
fieldName: 'Rating',
type: 'text'
},
];

@wire(accountRecords)
wiredAccounts({ error, data }) {
if (data) {
this.fetchedAccounts = data;
} else if (error) {
console.log(error);
}
}

handleSave( event ) {
const updatedFields = event.detail.draftValues;

updateAccounts( { data: updatedFields } )


.then( result => {

this.dispatchEvent(
new ShowToastEvent({
title: 'Success',
message: 'Accounts updated',
variant: 'success'
})
);

}).catch( error => {

this.dispatchEvent(
new ShowToastEvent({
title: 'Error updating records',
message: error,
variant: 'error'
})
);
});
}
}

Apex Method:-

public class ControllerClass {

@AuraEnabled(cacheable=true)
public static List<Account> accountRecords() {
return [SELECT Id, Name, Rating, Website, Type, AnnualRevenue,
Phone FROM Account];
}

@AuraEnabled
public static string updateAccounts(Object data) {
List <Account> accsForUpdate =
(List<Account>)JSON.deserialize(JSON.serialize(data), List<Account>.class);
update accsForUpdate;
}

2. Lightning Data Table with clickable column:-

lightningDatatableComponent.html

<template>
<lightning-card title="Lightning Datatable">
<lightning-datatable data={fetchedAccounts}
columns={columns}
key-field="Id">

</lightning-datatable>
</lightning-card>
</template>

lightningDatatableComponent.js

import { LightningElement, wire } from 'lwc';


import accountRecords from
'@salesforce/apex/LWC_ControllerClass.accRecords';

export default class LightningDatatableComponent extends LightningElement


{

fetchedAccounts;

columns = [{
label: "Account Name",
fieldName: 'accLink',
type: 'url',
typeAttributes: { label: { fieldName: 'Name' }, target: '_blank' }
},
{
label: "Type",
fieldName: 'Type',
type: 'text'
},
{
label: "Annual Revenue",
fieldName: 'AnnualRevenue',
type: 'Currency',
},
{
label: "Phone",
fieldName: 'Phone',
type: 'phone'
},
{
label: "Website",
fieldName: 'Website',
type: 'url'
},
{
label: "Rating",
fieldName: 'Rating',
type: 'text'
}];

@wire(accountRecords)
wiredAccounts({error, data}) {
if(data) {
data = JSON.parse(JSON.stringify(data));

data.forEach(res => {
res.accLink = '/' + res.Id;
});

this.fetchedAccounts = data;
} else if(error) {
console.log(error);
}
}
}

https://techdicer.com/add-hyperlink-column-in-lwc-datatable/
23rd August 2023

1. Navigation Service in LWC:-

● The lightning/navigation service is supported only in Lightning Experience.


● We can use navigation services in LWC to Navigate to Pages, Records, and
Lists.
● Use the navigation service, lightning/navigation, to navigate to many different
page types, like records, list views, and objects. Also use the navigation
service to open files.
● Firstly import it in the JavaScript file:-
import { NavigationMixin } from 'lightning/navigation';

● Next apply NavigationMixin function to component’s base class


export default class NavigationServiceComponent extends
NavigationMixin(LightningElement)

● You can follow the below links for better understanding


○ https://www.apexhours.com/navigation-service-in-lightning-web-comp
onents/
○ https://www.sfdcpoint.com/salesforce/navigation-service-in-lwc/
○ https://www.mstsolutions.com/technical/rendering-and-navigation-in-lw
c/

● Examples discussed in the session:-

1) Navigate to Case New Page

navigationComponent.html

<template>
<lightning-card title="Navigation Service">
<div class="slds-p-left_medium">
<lightning-button label="New Case"
onclick={navigateToNewCasePage}>
</lightning-button>
</div>
</lightning-card>
</template>

navigationComponent.js

export default class NavigationComponent extends


NavigationMixin(LightningElement) {
navigateToNewCasePage() {
this[NavigationMixin.Navigate]({
type: 'standard__objectPage',
attributes: {
objectApiName: 'Case',
actionName: 'new'
},
});
}
}

2) Navigate to Case Home Page

navigationComponent.html

<template>
<lightning-card title="Case Home Page Navigation">
<div class="slds-p-left_medium">
<a href={refUrl} onclick={handleNavigationClick}>Case
Home</a>
</div>
</lightning-card>
</template>

navigationComponent.js

export default class NavigationComponent extends


NavigationMixin(LightningElement) {

refUrl;

connectedCallback() {
this.caseHomePageRef = {
type: 'standard__objectPage',
attributes: {
objectApiName: 'Case',
actionName: 'home'
}
};
this[NavigationMixin.GenerateUrl](this.caseHomePageRef)
.then(url => this.refUrl = url);
}
handleNavigationClick(evt) {
//evt.preventDefault();
//evt.stopPropagation();
this[NavigationMixin.Navigate](this.caseHomePageRef);
}
}

3) Navigate to a Record Page

navigationComponent.html

<template>
<lightning-card title="Case Record Page Navigation">
<div class="slds-p-left_medium">
<lightning-button label="Record Page"
onclick={navigateToViewCasePage}>
</lightning-button>
</div>
</lightning-card>
</template>

navigationComponent.js

export default class NavigationComponent extends


NavigationMixin(LightningElement) {

recordId = '5005g00000gPnAKAA0';

navigateToViewCasePage() {
this[NavigationMixin.Navigate]({
type: 'standard__recordPage',
attributes: {
recordId: this.recordId,
objectApiName: 'Case',
actionName: 'view'
},
});
}
}

2. Lightning Datatable with Lightning Button Menu


lightningDatatableComponent.html

<template>
<lightning-card title="Lightning Data Table">

<lightning-datatable data={fetchedAccounts}
columns={columns}
key-field="Id"
onrowaction={handleRowAction}>
</lightning-datatable>

</lightning-card>
</template>

lightningDatatableComponent.js

import { LightningElement, wire } from 'lwc';


import { NavigationMixin } from 'lightning/navigation';
import accountRecords from
'@salesforce/apex/LWC_ControllerClass.accRecords';
import { deleteRecord } from 'lightning/uiRecordApi';
import { ShowToastEvent } from 'lightning/platformShowToastEvent';
import { refreshApex } from '@salesforce/apex';

export default class LightningDatatableComponent extends


NavigationMixin(LightningElement) {

fetchedAccounts; //accountList
wiredAccountList;
actions = [
{label: 'View', name: 'view'},
{label: 'Edit', name: 'edit'},
{label: 'Delete', name: 'delete'}
];

columns = [{
label: 'Account name',
fieldName: 'Name',
type: 'text'
},
{
label: 'Type',
fieldName: 'Type',
type: 'text'
},
{
label: 'Annual Revenue',
fieldName: 'AnnualRevenue',
type: 'Currency'
},
{
label: 'Phone',
fieldName: 'Phone',
type: 'phone'
},
{
label: 'Website',
fieldName: 'Website',
type: 'url'
},
{
label: 'Rating',
fieldName: 'Rating',
type: 'text'
},
{
type: 'action',
typeAttributes: { rowActions: this.actions },
}
];

@wire(accountRecords) accList(result) {
this.wiredAccountList = result;

if (result.data) {
this.fetchedAccounts = result.data;
this.error = undefined;
} else if (result.error) {
this.error = result.error;
this.fetchedAccounts = [];
}
}

handleRowAction(event) {
console.log('Handle Row Method ran');
console.log('Clicked row record Id ==> '+event.detail.row.Id);

if(event.detail.action.name === 'view') {


this[NavigationMixin.Navigate]({
type: 'standard__recordPage',
attributes: {
recordId: event.detail.row.Id,
objectApiName: 'Account',
actionName: 'view'
},
});
} else if(event.detail.action.name === 'edit') {
this[NavigationMixin.Navigate]({
type: 'standard__recordPage',
attributes: {
recordId: event.detail.row.Id,
objectApiName: 'Account',
actionName: 'edit'
},
});
console.log('Component is ready to get refreshed');
return refreshApex(this.wiredAccountList);
} else if(event.detail.action.name === 'delete') {
deleteRecord(event.detail.row.Id)
.then(() => {
this.dispatchEvent(
new ShowToastEvent({
title: 'Success',
message: 'Record deleted',
variant: 'success'
})
);
return refreshApex(this.wiredAccountList);
})
.catch(error => {
this.dispatchEvent(
new ShowToastEvent({
title: 'Error deleting record',
message: error.body.message,
variant: 'error'
})
);
});
}
}
}

https://www.infallibletechie.com/2020/03/lightning-datatable-with-buttonsrow.h
tml
24th August 2023
1. Pub Sub Model (Unrelated Components):-

● Publish-Subscribe (pubsub) Model in LWC is used to make communication


between two independent components.
● Please note that the Publish-Subscribe Model only works for components that
are on the same page.

● PubSub model is essentially setting up a channel for communication across


DOM (between sibling components), where one component (publisher) could
fire an event and all other components (subscribers) would respond to the
event via registered listeners.
● Let’s take a look at an example:- There are two components and both
components do not have any relation. As a Developer, we need to make them
talk & transfer the data from one component to another component.
● Create a component called as “pubsub” delete the HTML file from this. Only js
and meta xml file should be present. This component will behave as a
channel/messanger to communicate between two unrelated components.

● How data is transferred?

1) Event is fired from Publisher component

Syntax:-
fireEvent(this.pageRef, “eventName”, variableToPass);

Reference:-
- pageRef is CurrentPageReference.
- eventName is the name of your event, which will be same
while handling the event.
- variableToPass is the data you want to transfer.

2) Event is handled in Subcriber component

Syntax:-
connectedCallback() {
registerListener(“eventName”,
this.variableValueReceived, this);
}

Reference:-
- eventName is the name of your event, that is passed from
publisher component.
- variableValueReceived is the data that you will receive from
publisher’s variableToPass.
- this is just a PageReference.

● You can copy this component (pubsub) code from the below link:-
https://github.com/developerforce/pubsub/tree/master/force-app/main/default/l
wc/pubsub
● Understand deeply by looking at the below example:-

pubsub Component:-

pubsub.js

/**
* A basic pub-sub mechanism for sibling component communication
*
* TODO - adopt standard flexipage sibling communication mechanism when
it's available.
*/

const events = {};

/**
* Confirm that two page references have the same attributes
* @param {object} pageRef1 - The first page reference
* @param {object} pageRef2 - The second page reference
*/
const samePageRef = (pageRef1, pageRef2) => {
const obj1 = pageRef1.attributes;
const obj2 = pageRef2.attributes;
return Object.keys(obj1)
.concat(Object.keys(obj2))
.every((key) => {
return obj1[key] === obj2[key];
});
};

/**
* Registers a callback for an event
* @param {string} eventName - Name of the event to listen for.
* @param {function} callback - Function to invoke when said event is fired.
* @param {object} thisArg - The value to be passed as the this parameter to
the callback function is bound.
*/
const registerListener = (eventName, callback, thisArg) => {
// Checking that the listener has a pageRef property. We rely on that
property for filtering purpose in fireEvent()
if (!thisArg.pageRef) {
throw new Error(
'pubsub listeners need a "@wire(CurrentPageReference) pageRef"
property'
);
}

if (!events[eventName]) {
events[eventName] = [];
}
const duplicate = events[eventName].find((listener) => {
return listener.callback === callback && listener.thisArg === thisArg;
});
if (!duplicate) {
events[eventName].push({ callback, thisArg });
}
};

/**
* Unregisters a callback for an event
* @param {string} eventName - Name of the event to unregister from.
* @param {function} callback - Function to unregister.
* @param {object} thisArg - The value to be passed as the this parameter to
the callback function is bound.
*/
const unregisterListener = (eventName, callback, thisArg) => {
if (events[eventName]) {
events[eventName] = events[eventName].filter(
(listener) =>
listener.callback !== callback || listener.thisArg !== thisArg
);
}
};

/**
* Unregisters all event listeners bound to an object.
* @param {object} thisArg - All the callbacks bound to this object will be
removed.
*/
const unregisterAllListeners = (thisArg) => {
Object.keys(events).forEach((eventName) => {
events[eventName] = events[eventName].filter(
(listener) => listener.thisArg !== thisArg
);
});
};

/**
* Fires an event to listeners.
* @param {object} pageRef - Reference of the page that represents the
event scope.
* @param {string} eventName - Name of the event to fire.
* @param {*} payload - Payload of the event to fire.
*/
const fireEvent = (pageRef, eventName, payload) => {
if (events[eventName]) {
const listeners = events[eventName];
listeners.forEach((listener) => {
if (samePageRef(pageRef, listener.thisArg.pageRef)) {
try {
listener.callback.call(listener.thisArg, payload);
} catch (error) {
// fail silently
}
}
});
}
};

export {
registerListener,
unregisterListener,
unregisterAllListeners,
fireEvent
};
Publisher Component:-

publisherComponent.html

<template>

<lightning-card title="Publisher Component">


<div class="slds-p-around_medium lgc-bg">
<lightning-input type="text"
label="Enter some text"
onchange={handleChange}>
</lightning-input>
</div>

<lightning-button variant="brand"
label="Publish Data"
onclick={publishData}
class="slds-m-left_x-small">
</lightning-button>
</lightning-card>
</template>

publisherComponent.js

import { LightningElement, wire } from 'lwc';


import { CurrentPageReference } from 'lightning/navigation';
import { fireEvent } from 'c/pubsub';

export default class PublisherComponent extends LightningElement {

inputValue;

@wire(CurrentPageReference) pageRef;

handleChange(event) {
this.inputValue = event.target.value;
}

publishData() {
fireEvent(this.pageRef, 'parentPublisher', this.inputValue);
}
}

Subscriber Component:-
subscriberComponent.html

<template>

<lightning-card title="Subscriber Component">


Value from Publisher Component is: {receivedValue}
</lightning-card>

</template>

subscriberComponent.js

import { LightningElement, wire } from 'lwc';


import { CurrentPageReference } from 'lightning/navigation';
import { registerListener } from 'c/pubsub';

export default class SubscriberComponent extends LightningElement {

receivedValue;

@wire(CurrentPageReference) pageRef;

connectedCallback() {
registerListener('parentPublisher', this.handlePublisherMethod, this);
}

handlePublisherMethod(data) {
this.receivedValue = data;
}
}

You might also like