Sample code:
Apex Class:
public class LightningDualListSearchController {
@AuraEnabled( cacheable = true )
public static List < OptionWrapper > fetchAccounts() {
List < OptionWrapper > listAccounts = new List < OptionWrapper >();
for ( Account acc : [ SELECT Id, Name FROM Account LIMIT 10 ] ) {
listAccounts.add( new OptionWrapper( acc.Name, acc.Id ) );
}
return listAccounts;
}
public class OptionWrapper {
@AuraEnabled
public String label;
@AuraEnabled
public String value;
public OptionWrapper( String label, String value ) {
this.label = label;
this.value = value;
}
}
}
Lightning Web Component:
HTML:
<template>
<lightning-card>
<div class="slds-m-around_medium">
<lightning-input type="text" label="Search Account" onchange={handleSearchChange}></lightning-input><br/><br/>
<lightning-button label="Search" variant="brand" onclick={handleSearch}></lightning-button><br/><br/>
<lightning-dual-listbox
label="Select/Remove Accounts"
source-label="Available Accounts"
selected-label="Selected Accounts"
options={availableAccounts}
onchange={handleAccountChange}>
</lightning-dual-listbox>
</div>
</lightning-card>
</template>
JavaScript:
import { LightningElement, wire } from 'lwc';
import fetchAccounts from '@salesforce/apex/LightningDualListSearchController.fetchAccounts';
export default class LightningDualListSearch extends LightningElement {
availableAccounts;
searchString;
initialRecords;
@wire( fetchAccounts )
wiredRecs( { error, data } ) {
if ( data ) {
console.log( 'Records are ' + JSON.stringify( data ) );
this.availableAccounts = data;
this.initialRecords = data;
} else if ( error ) {
console.log( 'Error ' + JSON.stringify( error ) );
}
}
handleAccountChange( event ) {
const selectedOptionsList = event.detail.value;
console.log( 'Selected Options are ' + JSON.stringify( selectedOptionsList ) );
}
handleSearchChange( event ) {
this.searchString = event.detail.value;
console.log( 'Search String is ' + this.searchString );
}
handleSearch( event ) {
console.log( 'Search String is ' + this.searchString );
if ( this.searchString ) {
this.availableAccounts = this.initialRecords;
if ( this.availableAccounts ) {
let recs = [];
for ( let rec of this.availableAccounts ) {
if ( rec.label.toLowerCase().includes( this.searchString ) ) {
recs.push( rec );
}
}
console.log( 'Matched Accounts are ' + JSON.stringify( recs ) );
this.availableAccounts = recs;
}
} else {
this.availableAccounts = this.initialRecords;
}
}
}
JS-meta.xml:
<?xml version="1.0" encoding="UTF-8"?>
<LightningComponentBundle xmlns="http://soap.sforce.com/2006/04/metadata">
<apiVersion>52.0</apiVersion>
<isExposed>true</isExposed>
<targets>
<target>lightning__Tab</target>
</targets>
</LightningComponentBundle>
Output: