Endlwc
Endlwc
● 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.
Step 1:- Open Command Palette (Ctrl + Shift + P) in your VS Code and select option
“>SFDX: Create Project with Manifest”
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)
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:-
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)
● 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:
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.
<p>{message}</p>
<template>
<lightning-card title="Hello World Component">
<div class="slds-p-left_medium">
Hello World.
</div>
</lightning-card>
</template>
helloWorld.js-meta.xml
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
b. Example 2:-
{
var i = 10;
console.log(i); //10
}
console.log(i); //10
c. Example 3:-
{
var i = 10;
console.log(i); //10
var i = 20;
}
console.log(i); //20
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);
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
firstName;
lastName;
handleInput(event) {
if(event.target.name == 'firstName') {
this.firstName = 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
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;
}
}
}
variant String The theme and icon displayed in the toast. Valid
values are:
● Info – (Default) A gray box with an info
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.
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>
<lightning-button variant="Success"
label="Success"
onclick={successButton}
class="slds-m-left_x-small">
</lightning-button>
<lightning-button variant="destructive-text"
label="Warning"
onclick={warningButton}
class="slds-m-left_x-small">
</lightning-button>
<lightning-button variant="destructive"
label="Error"
onclick={errorButton}
class="slds-m-left_x-small">
</lightning-button>
</div>
</lightning-card>
</template>
toastComponent.js
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);
}
}
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
Child Component:-
childComponent.html
<template>
<lightning-card>
Hello World from Child Component
</lightning-card>
</template>
4. Decorators:-
1. Api
2. Track
3. Wire
1. Api:-
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
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
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
@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">
<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
@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;
}
3. Wire:-
● 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
’;
if(data) {
//This will run if Apex has no error
}
Else if(error) {
//This will run if Apex has any error.
}
}
● 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
’;\
LWC_ControllerClass.apxc
@AuraEnabled(cacheable=true)
public static List<Account> accRecords() {
System.debug('Method is called');
return [SELECT Id, Name FROM Account LIMIT 10];
}
}
wireComponent.html
<template>
<lightning-card title="Wire Decorator Component">
<template if:true={fetchedAccounts}>
<table>
<tr>
<th>Id</th>
<th>Name</th>
</tr>
wireComponent.js
import { LightningElement, track, wire } from 'lwc';
import accountRecords from
'@salesforce/apex/LWC_ControllerClass.accRecords';
@track
fetchedAccounts;
@wire(accountRecords)
wiredAccounts({error, data}) {
if(data) {
this.fetchedAccounts = data;
} else if(error) {
console.log(error);
}
}
}
wireComponent.html
<template>
<lightning-card title="Wire Decorator Component">
<template if:true={fetchedAccounts.data}>
<table>
<tr>
<th>Id</th>
<th>Name</th>
</tr>
<template if:true={fetchedAccounts.error}>
Apex Error
</template>
</lightning-card>
</template>
wireComponent.js
@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>
imperativeComponent.js
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>
LWC_ControllerClass.apxc
@AuraEnabled(cacheable=true)
public static List<Account> accRecords(String inputName) {
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>
imperativeComponent.js
showTable = false;
@track fetchedAccounts;
handleInput(event) {
Parent Component:-
parentComponent.html
<template>
<lightning-card title="Parent Component">
</c-child-component>
</lightning-card>
</template>
parentComponent.js
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
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
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/
Parent Component:-
parentComponent.html
<template>
<lightning-card>
Parent Component
<c-child-component></c-child-component>
</lightning-card>
</template>
parentComponent.js
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
constructor() {
super();
console.log('Inside child constructor');
}
connectedCallback() {
console.log('Inside child connectedCallback');
}
renderedCallback() {
console.log('Inside child renderedCallback');
}
}
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
connectedCallback() {
console.log('Inside parent connectedCallback');
}
renderedCallback() {
console.log('Inside parent
renderedCallback'+this.template.querySelector('[data-id="secondButton"]').lab
el);
}
}
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
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';
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
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
disconnectedCallback() {
console.log('Inside child disconnected callback');
}
}
F) ErrorCallback:-
Parent Component:-
parentComponent.html
<template>
<lightning-card title="Parent Component">
<c-child-component></c-child-component>
</lightning-card>
</template>
parentComponent.js
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
handlePercent(event) {
if(parseInt(event.target.value) > 100 ||
parseInt(event.target.value) < 0) {
throw new Error('Invalid percentage');
}
}
}
😝
special routine called "lifecycle." Let's see what happens at each stage of this routine
with some fun examples.
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.
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.
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.
● 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 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:-
● 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>
</lightning-card>
</template>
ldsComponent.js
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
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:-
1) Editing a Record:-
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
handleSubmit(event) {
handleSuccess(event) {
console.log('onsuccess event
recordEditForm'+event.detail.id);
}
}
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
recordId = '0015g00000n9m4uAAA';
}
○ 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.
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
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:-
@AuraEnabled(cacheable=true)
public static List<Account> accountRecords() {
return [SELECT Id, Name, Rating, Website, Type, AnnualRevenue,
Phone FROM Account];
}
}
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
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;
this.dispatchEvent(
new ShowToastEvent({
title: 'Success',
message: 'Accounts updated',
variant: 'success'
})
);
this.dispatchEvent(
new ShowToastEvent({
title: 'Error updating records',
message: error,
variant: 'error'
})
);
});
}
}
Apex Method:-
@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;
}
lightningDatatableComponent.html
<template>
<lightning-card title="Lightning Datatable">
<lightning-datatable data={fetchedAccounts}
columns={columns}
key-field="Id">
</lightning-datatable>
</lightning-card>
</template>
lightningDatatableComponent.js
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
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
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
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);
}
}
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
recordId = '5005g00000gPnAKAA0';
navigateToViewCasePage() {
this[NavigationMixin.Navigate]({
type: 'standard__recordPage',
attributes: {
recordId: this.recordId,
objectApiName: 'Case',
actionName: 'view'
},
});
}
}
<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
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);
https://www.infallibletechie.com/2020/03/lightning-datatable-with-buttonsrow.h
tml
24th August 2023
1. Pub Sub Model (Unrelated Components):-
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.
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.
*/
/**
* 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-button variant="brand"
label="Publish Data"
onclick={publishData}
class="slds-m-left_x-small">
</lightning-button>
</lightning-card>
</template>
publisherComponent.js
inputValue;
@wire(CurrentPageReference) pageRef;
handleChange(event) {
this.inputValue = event.target.value;
}
publishData() {
fireEvent(this.pageRef, 'parentPublisher', this.inputValue);
}
}
Subscriber Component:-
subscriberComponent.html
<template>
</template>
subscriberComponent.js
receivedValue;
@wire(CurrentPageReference) pageRef;
connectedCallback() {
registerListener('parentPublisher', this.handlePublisherMethod, this);
}
handlePublisherMethod(data) {
this.receivedValue = data;
}
}