In my previous post, I have written about the reusable lookup lwc component. This post is an extension to it i.e., building reusable multi-lookup lwc component.
This reusable multi-lookup component can be used on any lightning web/aura components.
Now, let's reuse the above multiLookup component.
PS: Hope this helps! Please share your feedback/suggestions/any exciting posts you come across. Happy Coding!
This reusable multi-lookup component can be used on any lightning web/aura components.
multiLookup.html
<template>
<div class="slds-combobox_container" onmouseleave={hideOptions}>
<div class={comboBoxClass} aria-expanded={comboExpanded} aria-haspopup="listbox" role="combobox">
<div class="slds-combobox__form-element slds-input-has-icon slds-input-has-icon_right" role="none">
<input type="text" class="slds-input slds-combobox__input slds-combobox__input-value" id="combobox-id"
autocomplete="off" aria-controls="listbox-id" role="textbox" placeholder={placeHolder}
onkeyup={handleSearch} onclick={showOptions}></input>
<span class="slds-icon_container slds-icon-utility-search slds-input__icon slds-input__icon_right">
<lightning-icon icon-name="utility:search" size="x-small" class="slds-icon-text-default">
</lightning-icon>
</span>
</div>
<div id="listbox-id" class="slds-dropdown slds-dropdown_length-5 slds-dropdown_fluid vk-scrollbar"
role="listbox" onmouseleave={hideOptions}>
<ul class="slds-listbox slds-listbox_vertical" role="presentation">
<template for:each={optionsToDisplay} for:item="option" for:index="index">
<li role="presentation" class="slds-listbox__item" key={option} data-index={index}
onclick={handleSelection}>
<div class="slds-media slds-listbox__option slds-listbox__option_entity slds-listbox__option_has-meta"
role="option">
<span class="slds-media__figure slds-listbox__option-icon">
<lightning-icon lwc:if={option.isSelected} icon-name="utility:check" size="xx-small"
class="slds-current-color"></lightning-icon>
</span>
<span if:true={option.hasIcon} class="slds-media__figure slds-listbox__option-icon">
<span class="slds-icon_container">
<lightning-icon icon-name={option.icon} size="x-small"></lightning-icon>
</span>
</span>
<span class="slds-media__body">
<span class="slds-listbox__option-text slds-listbox__option-text_entity">
{option.label}
</span>
</span>
</div>
</li>
</template>
<li if:true={noResultsFound} class="slds-p-left_small">☹ No results found</li>
</ul>
</div>
</div>
</div>
<div if:true={showSelectedOptions} class="slds-listbox_selection-group">
<ul class="slds-listbox slds-listbox_horizontal" role="listbox" aria-label="Selected Options:"
aria-orientation="horizontal">
<template for:each={selectedOptions} for:item="opt" for:index="index">
<li class="slds-listbox-item" role="presentation" key={opt.index}>
<span class="slds-pill" role="option" tabindex="0" aria-selected="true">
<span if:true={opt.hasIcon} class="slds-icon_container slds-pill__icon_container">
<lightning-icon icon-name={opt.icon} size="x-small">
</lightning-icon>
</span>
<span class="slds-pill__label" title={opt.value}>{opt.value}</span>
<span class="slds-icon_container slds-pill__remove" title="Remove">
<lightning-button-icon name={index} variant="bare" icon-name="utility:close"
size="x-small" alternative-text="Remove selected option" onclick={removeSelectedOption}>
</lightning-button-icon>
</span>
</span>
</li>
</template>
</ul>
</div>
</template>
multiLookup.js
import { LightningElement, api, track } from "lwc";
const COMBO_BOX = "slds-combobox slds-dropdown-trigger slds-dropdown-trigger_click";
const IS_OPEN = " slds-is-open";
export default class MultiLookup extends LightningElement {
@api placeHolder = "Search...";
@track optionsToDisplay = [];
@track selectedOptions = [];
showSelectedOptions = false;
comboBoxClass = COMBO_BOX;
comboExpanded = false;
searchKey;
noResultsFound = false;
_options = [];
selOptionsMap = new Map();
@api
set options(value) {
value.forEach((elm, index) => {
let opt = { ...elm };
opt.index = index;
opt.hasIcon = opt.icon ? true : false;
opt.isSelected = false;
this.optionsToDisplay.push(opt);
this._options.push(opt);
});
}
get options() {
return this._options;
}
showOptions() {
this.comboExpanded = true;
this.comboBoxClass = COMBO_BOX + IS_OPEN;
}
hideOptions() {
this.comboExpanded = false;
this.comboBoxClass = COMBO_BOX;
}
handleSearch(event) {
const searchKey = event.target.value;
this.noResultsFound = false;
if (searchKey) {
this.optionsToDisplay = this._options.filter((obj) =>
obj.value.toLowerCase().includes(searchKey.toLowerCase())
);
if (this.optionsToDisplay.length === 0) this.noResultsFound = true;
this.showOptions();
} else {
this.hideOptions();
this.optionsToDisplay = this._options;
}
}
handleSelection(event) {
let index = Number(event.currentTarget.dataset.index);
let selOption = this.optionsToDisplay[index];
selOption.isSelected = !selOption.isSelected;
if (selOption.isSelected) this.selOptionsMap.set(selOption.index, selOption);
else this.selOptionsMap.delete(selOption.index);
this.sendSelectedOptions();
}
removeSelectedOption(event) {
let index = event.target.name;
let selOption = this.selectedOptions[index];
selOption.isSelected = false;
this.selOptionsMap.delete(selOption.index);
this.sendSelectedOptions();
}
sendSelectedOptions() {
this.selectedOptions = Array.from(this.selOptionsMap.values());
this.showSelectedOptions = this.selectedOptions.length > 0;
this.dispatchEvent(new CustomEvent("change", { detail: this.selectedOptions }));
}
@api //Method can be called from parent component
clear() {
this.selectedOptions = [];
this.selOptionsMap.forEach((val, key) => {
val.isSelected = false;
});
this.selOptionsMap = new Map();
this.showSelectedOptions = false;
this.template.querySelector(".slds-combobox__input-value").value = "";
this.optionsToDisplay = this._options;
}
}
multiLookup.css
.slds-input {
min-height: 1.5rem !important;
height: 1.7rem !important;
}
.slds-dropdown {
margin-top: 0 !important;
}
.slds-listbox_vertical .slds-listbox__option_has-meta .slds-media__figure {
margin-top: 1px;
}
.slds-listbox_vertical .slds-listbox__option_entity {
padding: 0.25rem;
}
.slds-listbox_vertical .slds-listbox__option_entity .slds-media__figure {
margin-right: 0.2rem;
}
.slds-listbox__option-icon .slds-current-color {
color: #0176d3;
}
.slds-listbox_selection-group {
padding-right: 0.75rem !important;
overflow: unset !important;
height: auto;
}
.slds-listbox_selection-group .slds-listbox-item {
padding: 0;
}
.slds-listbox_horizontal li + li,
.slds-listbox--horizontal li + li {
padding-left: 0;
}
.slds-pill__icon_container {
margin-right: 0;
}
.slds-pill__label {
margin-left: 0.25rem;
}
.vk-scrollbar::-webkit-scrollbar {
width: 7px;
height: 7px;
}
.vk-scrollbar::-webkit-scrollbar-track {
box-shadow: inset 0 0 6px #bfbfbf;
-webkit-box-shadow: inset 0 0 6px #bfbfbf;
border-radius: 0.25rem;
}
.vk-scrollbar::-webkit-scrollbar-thumb {
background: #95989d;
border-radius: 0.25rem;
}
.vk-scrollbar::-webkit-scrollbar-thumb:hover {
background: #313235;
}
Now, let's reuse the above multiLookup component.
multiLookupHolder.html
<template>
<lightning-card title="Multi-lookup Component">
<lightning-layout vertical-align="center">
<lightning-layout-item size="6" padding="around-small">
Selected Opportunities Id's: {selectedOppsIds}
<c-multi-lookup if:true={showOppLookup} options={opps} place-holder="Select Opportunities..."
onchange={handleOppsChange}></c-multi-lookup>
</lightning-layout-item>
</lightning-layout>
</lightning-card>
</template>
multiLookupHolder.js
import { LightningElement, track, wire } from 'lwc';
import getOpportunities from '@salesforce/apex/OpportunitiesController.getOpportunities';
export default class MultiLookupHolder extends LightningElement {
@track error;
@track opps = [];
@track showOppLookup = false;
@track selectedOppsIds;
@wire(getOpportunities)
wOpps({error,data}){
if(data){
for(let i=0; i<data.length; i++){
let obj = {value: data[i].Id, label: data[i].Name, icon:'standard:opportunity'};
this.opps.push(obj);
}
this.showOppLookup = true;
}else{
this.error = error;
}
}
//On Opportunities selection/clear
handleOppsChange(event){
let opps = event.detail;
this.selectedOppsIds = '';
opps.forEach(opp => {
this.selectedOppsIds += opp.value+'; ';
});
}
}
PS: Hope this helps! Please share your feedback/suggestions/any exciting posts you come across. Happy Coding!
Hi . Venky I have a Query if suppose i have four different list in that case how do i persist value across Lookup
ReplyDelete