How to Create Re-Usable and Lookup Dropdown Lightning Web Components?
- February 12, 2020
- 10 minutes
- 7051
Salesforce announced Lightning Web Components (LWC) in December 2018, with the comparison of the existing Aura Framework.
What Is Lightning Web Components?
Lightning Web Components is a new programming model for building Lightning components. It leverages the web standards discoveries of the previous five decades, may coexist and interoperate with the initial Aura programming version and also delivers exceptional performance. Lightning Web Components are custom elements built using HTML and modern JavaScript. Lightning Web Components take the Salesforce lightning platform one step closer to using web standards for UI development. It is beneficial for Salesforce lightning developer and The main benefit of using LWS is, it is fast, more secure and lightweight.
Advantages Of Lightning Web Components
- Reusability Of Components : we can make components reusable in other components which is more efficient for any web standard.
- Faster Loading and Lightweight : Lightning web component is faster and is a lightweight framework built on web standards.
- Better Performance : lightning web component is faster than aura components and more compatible.Since performance is key feature for development of any website.
- Easier For Developers In Learning : It is easy to learn lightning web components as it uses simple HTML markup, DOM and CSS concepts that are quite easier to learn.
This tutorial explains how to use one component multiple times in a lightning web page which we define as a reusable component.
For this, we will take an example of a dropdown lookup that shows a list of drivers and locations.
1. Create Apex Class For fetchLookUpValues
public with sharing class GetDriverData {
@AuraEnabled(cacheable=true)
public static List < sObject > fetchLookUpValues(String
searchKey,String
fieldName, String ObjectName,String keyField) {
List < sObject > returnList = new List < sObject > ();
String sQuery = 'select '+fieldName+','+keyField+ ' from '
+ObjectName+' LIMIT 5000' ;
List < sObject > lstOfRecords = Database.query(sQuery);
for (sObject obj: lstOfRecords) {
returnList.add(obj);
}
return returnList;
}
}
2. Create validateDataList Component
In this component, we will display a list of records need to display for the dropdown list. Here is the code for HTML markup & Javascript Class
validatDataList.html
<template>
<div class="slds-form-element">
<div class="slds-form-element__control">
<div class="slds-combobox_container">
<div class="slds-combobox slds-dropdown-trigger slds-dropdown-trigger_click slds-is-open"
aria-expanded="true" aria-haspopup="listbox" role="combobox">
<div class="slds-combobox__form-element slds-input-has-icon slds-input-has-icon_right" role="none">
<!-- hide this by default-->
<div class="selectedOption slds-hide">
<input type="text"
class="slds-input slds-combobox__input slds-combobox__input-value"
id="combobox-id-5" aria-controls="listbox-id-5" autocomplete="off" role="textbox"
placeholder="Select an Option" readonly="" value={selectedAccount} />
<button class="slds-button slds-button_icon slds-input__icon slds-input__icon_right"
title="Remove selected option">
<lightning-icon icon-name="utility:close" alternative-text="close" size="x-small"
onclick={handleRemoveSelectedOption}></lightning-icon>
<span class="slds-assistive-text">Remove selected option</span>
</button>
</div>
<!-- end hide this by default-->
<div class="defaultClass">
<input type="text" class="slds-input slds-combobox__input slds-has-focus searchvalue" id="combobox-id-3"
aria-activedescendant="option1" aria-autocomplete="list" list="listbox-id-3" aria-controls="listbox-id-3"
autocomplete="off" role="textbox" placeholder="Search..." onblur={handleBlur} onclick={handleClick} onkeyup={handleKeyUp}/>
<span class="slds-icon_container">
<lightning-icon icon-name="utility:search" class="slds-icon-utility-search slds-input__icon slds-input__icon_right slds-searchIcon" alternative-text="Approved" size="x-small">
</lightning-icon>
<lightning-icon icon-name="utility:down" class="slds-icon-utility-down slds-input__icon slds-input__icon_right slds-hide" size="x-small">
</lightning-icon>
</span>
</div>
</div>
<div id="listbox-id-3"
class="slds-dropdown slds-dropdown_length-with-icon-7 slds-dropdown_fluid accounts_list slds-hide"
role="listbox">
<ul class="slds-listbox slds-listbox_vertical" role="presentation">
<li role="presentation" class="slds-listbox__item">
<div aria-selected="true" id="option0"
class="slds-media slds-listbox__option slds-listbox__option_entity slds-listbox__option_term slds-has-focus"
role="option">
<span class="slds-media__figure slds-listbox__option-icon">
<span class="slds-icon_container slds-icon-utility-search"
title="Search for term: ">
<lightning-icon icon-name="utility:search" alternative-text="search"
size="x-small"></lightning-icon>
<span class="slds-assistive-text">Search for term:
</span>
</span>
</span>
<span class="slds-media__body">
<span
class="slds-listbox__option-text slds-listbox__option-text_entity">{searchValue}</span>
</span>
</div>
</li>
<template if:true={options}>
<template for:each={options} for:item="account">
<li role="presentation" class="slds-listbox__item" key={account.key}
onmousedown={handleOptionSelect} data-id={account.key} data-name={account.value}>
<div aria-selected="true" id={account.key}
class="slds-media slds-listbox__option slds-listbox__option_entity slds-listbox__option_has-meta"
role="option" tabindex="0">
<span class="slds-media__body">
<span
class="slds-listbox__option-text slds-listbox__option-text_entity slds_optiontxt">{account.value}</span>
</span>
</div>
</li>
</template>
</template>
<template if:false={options}>
<div>Error</div>
</template>
</ul>
</div>
</div>
</div>
</div>
</div>
</template>
validateDataList.js
import { LightningElement,api,wire,track} from 'lwc';
import fetchLookUpValues from '@salesforce/apex/GetDriverData.fetchLookUpValues';
export default class ValidateDataListComponent extends LightningElement {
@track options = [];
@api searchKey;
@track searchValue = '';
@api objectName;
@api fieldName;
@api keyField;
@track selectedAccount;
@track showAccountsListFlag = false;
@track isSelection = false;
@wire(fetchLookUpValues,{searchKey:'$searchKey',fieldName:'$fieldName',ObjectName:'$objectName',keyField:'$keyField'})
picklistvalues({data,error}){
if(data){
let picklistOptions = [{ key: '--None--', value: '--None--'}];
data.forEach(key=>{
picklistOptions.push({
key:key[this.keyField],
value:key[this.fieldName]
});
});
this.options = picklistOptions;
}
else if(error){
console.log(error);
}
}
handleClick(){
if (!this.showAccountsListFlag) {
this.showAccountsListFlag = true;
this.template
.querySelector('.accounts_list')
.classList.remove('slds-hide');
this.template
.querySelector('.slds-searchIcon')
.classList.add('slds-hide');
this.template
.querySelector('.slds-icon-utility-down')
.classList.remove('slds-hide');
}
this.template
.querySelector('.slds-dropdown-trigger')
.classList.add('slds-is-open');
}
handleKeyUp(event) {
window.clearTimeout(this.delayTimeout);
this.searchValue = event.target.value;
const filter = this.searchValue.toUpperCase();
const span = this.template.querySelector('.slds-listbox_vertical').childNodes;
for (let i = 1; i < span.length; i++) {
const option = span[i].textContent;
if (option.toUpperCase().indexOf(filter) > -1) {
span[i].style.display = "";
} else {
span[i].style.display = "none";
}
}
// eslint-disable-next-line @lwc/lwc/no-async-operation
this.searchValue = this.searchValue;
if (this.searchValue === ''){
this.template
.querySelector('.accounts_list')
.classList.add('slds-hide');
this.template
.querySelector('.slds-searchIcon')
.classList.remove('slds-hide');
this.template
.querySelector('.slds-icon-utility-down')
.classList.add('slds-hide');
this.showAccountsListFlag = false;
}
}
handleOptionSelect(event) {
this.selectedAccount = event.currentTarget.dataset.name;
if(!this.isSelection){
this.isSelection = true;
}
console.log(this.isSelection);
this.template
.querySelector('.selectedOption')
.classList.remove('slds-hide');
this.template
.querySelector('.accounts_list')
.classList.add('slds-hide');
}
handleRemoveSelectedOption() {
this.template
.querySelector('.selectedOption')
.classList.add('slds-hide');
this.template
.querySelector('.slds-searchIcon')
.classList.remove('slds-hide');
this.template
.querySelector('.slds-icon-utility-down')
.classList.add('slds-hide');
this.template.querySelector('.searchvalue').value = '';
this.searchKey = '';
this.showAccountsListFlag = false;
}
}
To get the values in the dropdown list we can use ‘fetchLookUpValues’ wire adapters. This wire adapter uses ‘@salesforce/apex/GetDriverData.fetchLookUpValues’ in which GetDriverData is Apex class and fetchLookUpValues is method name of apex class.
Picklist values will get data from wire adapters which will bind to HTML as options.
Configuration File:
<?xml version="1.0" encoding="UTF-8"?>
<LightningComponentBundle xmlns="http://soap.sforce.com/2006/04/metadata">
<apiVersion>47.0</apiVersion>
<isExposed>true</isExposed>
<targets>
<target>lightning__AppPage</target>
<target>lightning__RecordPage</target>
<target>lightning__HomePage</target>
</targets>
</LightningComponentBundle>
3. Create reusableLookup Component
Here resuableLookup Component acts as a parent component that contains validateDatalist as child components.
In this component, we are using a reusable component named validateDataListComponent.
To make component reusable we need the following parameters as an attribute for validateDataListComponent :
- field-name : Name of the field need to display data for drop-down list for example ‘Drivers Name’ and ‘Trip Destination’.
- key-field : field which will act as a key for data.
- object-name : object API name of custom objects.
- search-key: will be the same as a field name.
Here is the code for the Html markup.
reusableLookup.html
<template>
<div class="slds-box">
<div class="slds-grid slds-gutters">
<div class="slds-col">
<label class="slds-form-element__label">Drivers</label>
<c-validate-data-list-component field-name="Name" key-field="Id" object-name="Contact" search-key="Name" >
</c-validate-data-list-component>
</div>
<div class="slds-col">
<label class="slds-form-element__label">Location</label>
<c-validate-data-list-component field-name="Trip_Destination__c" key-field="Destination_Name__c"
object-name="Employee_Mileage__c" search-key="Trip_Destination__c" ></c-validate-data-list-component>
</div>
</div>
</div>
</template>
Here is one component, we have useful data for drivers and in other we have data for the location.
4. Create a Visualforce Page to introduce Lightning Web Component
<apex:page >
<apex:includeLightning />
<div id="lightning" />
<script>
$Lightning.use("c:reusableApp", function() {
$Lightning.createComponent("c:reusableLookup", {
objectName: "Contact"
},
"lightning",
function(cmp) {
console.log("LWC component was created");
// do some stuff
}
);
});
</script>
</apex:page>
5. Create Demo App and test lookup
If you are thinking about building your app on the AppExchange, Contact us. At GetOnCRM Solutions, Our team of highly experienced Salesforce Lightning Experts can help you to customize and build beautiful apps and future for your platform on your unique business needs.