Lightning Web Components: Multi Select Custom Lookup

Lightning Web Components (LWC) is current Trending technology in Salesforce Lightning Eco System. I have shared many post related to LWC which you can check to quickly get the idea. Today I will share Multi Select Custom Lookup LWC.

Multi Select Custom lookup in lightning Web Component LWC

Previously I have shared Custom Lookup in Lightning web Component but in that we can only select one record, using multi select we can select n number of records. As this is generic component so you can use it with any object.

Now we will check the code part.

lwcMultiLookup.html

<template>
    <lightning-card>
        <h3 slot="title">
            <lightning-icon icon-name="utility:connected_apps" size="small"></lightning-icon>
            Multi Select Custom Lookup in Lightning Web Components
        </h3>
        <div slot="footer">
                
        </div>
        <div>
            <div class="slds-form-element">
                
                <div class="slds-form-element__control">
                    <div class="slds-combobox_container">
                        
                        <div class={txtclassname} data-id="resultBox" aria-expanded="false" aria-haspopup="listbox" role="combobox">
                            <div class="slds-form-element__control slds-input-has-icon slds-input-has-icon slds-input-has-icon_left-right" role="none">
                                
                                <div>
                                    <span class="slds-icon_container slds-icon-utility-search slds-input__icon iconheight">
                                        <lightning-icon class="slds-icon slds-icon slds-icon_small slds-icon-text-default" icon-name={iconName} size="x-small" alternative-text="icon" ></lightning-icon>
                                    </span> 
                                </div>
                                <lightning-input required={required} data-id="userinput" label={Label} name="searchText" onchange={searchField} class="leftspace"></lightning-input>
                                <span class="slds-icon_container slds-icon-utility-search slds-input__icon slds-input__icon_right iconheight">
                                    <lightning-icon class="slds-icon slds-icon slds-icon_small slds-icon-text-default" icon-name="utility:search" size="x-small" alternative-text="icon" ></lightning-icon>
                                </span>
                            </div>
                            <div class="slds-form-element__control slds-input-has-icon slds-input-has-icon slds-input-has-icon_left-right" role="none">
                                <template for:each={selectedRecords} for:item="serecord">
                                    <span key={serecord.recId}>
                                    <lightning-pill label={serecord.recName} name={serecord.recId} onremove={removeRecord}>
                                            <lightning-icon icon-name={iconName} variant="circle" alternative-text={serecord.recName}></lightning-icon>
                                        </lightning-pill>
                                    </span>
                                </template>
                            </div>
                        
                            <!-- Second part display result -->
                            <div id="listbox-id-1" class="slds-dropdown slds-dropdown_length-with-icon-7 slds-dropdown_fluid" role="listbox">
                                <ul class="slds-listbox slds-listbox_vertical" role="presentation">
                                    <template for:each={searchRecords} for:item="serecord">
                                        <li role="presentation" class="slds-listbox__item" key={serecord.recId}>
                                            
                                            <div data-id={serecord.recId} data-name={serecord.recName} onclick={setSelectedRecord} class="slds-media slds-listbox__option slds-listbox__option_entity slds-listbox__option_has-meta" role="option">
                                                <span class="slds-media__figure">
                                                    <span class="slds-icon_container slds-icon-standard-account">
                                                        <lightning-icon icon-name={iconName} class="slds-icon slds-icon slds-icon_small slds-icon-text-default" size="x-small"></lightning-icon>
                                                    </span>
                                                </span>
                                                <span class="slds-media__body">
                                                    <span class="slds-listbox__option-text slds-listbox__option-text_entity">{serecord.recName}</span>
                                                    <span class="slds-listbox__option-meta slds-listbox__option-meta_entity">{objectName} • {serecord.recName}</span>
                                                </span>
                                            </div>
                                        </li>
                                    </template>
                                </ul>
                            </div>
                            <div if:true={messageFlag}>
                                No result found.
                            </div>
                            <div if:true={LoadingText}>
                                Loading...
                            </div>
                        </div>
                    </div>
                </div>
            </div>
        </div>
    </lightning-card>
</template>

lwcMultiLookup.js

import { LightningElement,api,track } from 'lwc';
import getResults from '@salesforce/apex/lwcMultiLookupController.getResults';

export default class LwcMultiLookup extends LightningElement {
    @api objectName = 'Account';
    @api fieldName = 'Name';
    @api Label;
    @track searchRecords = [];
    @track selectedRecords = [];
    @api required = false;
    @api iconName = 'action:new_account'
    @api LoadingText = false;
    @track txtclassname = 'slds-combobox slds-dropdown-trigger slds-dropdown-trigger_click';
    @track messageFlag = false;
 
    searchField(event) {

        var currentText = event.target.value;
        var selectRecId = [];
        for(let i = 0; i < this.selectedRecords.length; i++){
            selectRecId.push(this.selectedRecords[i].recId);
        }
        this.LoadingText = true;
        getResults({ ObjectName: this.objectName, fieldName: this.fieldName, value: currentText, selectedRecId : selectRecId })
        .then(result => {
            this.searchRecords= result;
            this.LoadingText = false;
            
            this.txtclassname =  result.length > 0 ? 'slds-combobox slds-dropdown-trigger slds-dropdown-trigger_click slds-is-open' : 'slds-combobox slds-dropdown-trigger slds-dropdown-trigger_click';
            if(currentText.length > 0 && result.length == 0) {
                this.messageFlag = true;
            }
            else {
                this.messageFlag = false;
            }

            if(this.selectRecordId != null && this.selectRecordId.length > 0) {
                this.iconFlag = false;
                this.clearIconFlag = true;
            }
            else {
                this.iconFlag = true;
                this.clearIconFlag = false;
            }
        })
        .catch(error => {
            console.log('-------error-------------'+error);
            console.log(error);
        });
        
    }
    
   setSelectedRecord(event) {
        var recId = event.currentTarget.dataset.id;
        var selectName = event.currentTarget.dataset.name;
        let newsObject = { 'recId' : recId ,'recName' : selectName };
        this.selectedRecords.push(newsObject);
        this.txtclassname =  'slds-combobox slds-dropdown-trigger slds-dropdown-trigger_click';
        let selRecords = this.selectedRecords;
		this.template.querySelectorAll('lightning-input').forEach(each => {
            each.value = '';
        });
        const selectedEvent = new CustomEvent('selected', { detail: {selRecords}, });
        // Dispatches the event.
        this.dispatchEvent(selectedEvent);
    }

    removeRecord (event){
        let selectRecId = [];
        for(let i = 0; i < this.selectedRecords.length; i++){
            if(event.detail.name !== this.selectedRecords[i].recId)
                selectRecId.push(this.selectedRecords[i]);
        }
        this.selectedRecords = [...selectRecId];
        let selRecords = this.selectedRecords;
        const selectedEvent = new CustomEvent('selected', { detail: {selRecords}, });
        // Dispatches the event.
        this.dispatchEvent(selectedEvent);
    }
}

lwcMultiLookupController .cls

public with sharing class lwcMultiLookupController {
    public lwcMultiLookupController() {

    }
    @AuraEnabled(cacheable=true)
    public static List<SObJectResult> getResults(String ObjectName, String fieldName, String value, List<String> selectedRecId) {
        List<SObJectResult> sObjectResultList = new List<SObJectResult>();
        system.debug(fieldName+'-------------'+ObjectName+'---++----------'+value+'====='+selectedRecId);
        if(selectedRecId == null)
            selectedRecId = new List<String>();

        if(String.isNotEmpty(value)) {
            String query = 'Select Id,'+fieldName+' FROM '+ObjectName+' WHERE '+fieldName+' LIKE \'%' + value.trim() + '%\' and ID NOT IN: selectedRecId';
            system.debug(query);
            for(sObject so : Database.Query(query)) {
                String fieldvalue = (String)so.get(fieldName);
                sObjectResultList.add(new SObjectResult(fieldvalue, so.Id));
            }
        }
        return sObjectResultList;
    }
    
    public class SObjectResult {
        @AuraEnabled
        public String recName;
        @AuraEnabled
        public Id recId;
        
        public SObJectResult(String recNameTemp, Id recIdTemp) {
            recName = recNameTemp;
            recId = recIdTemp;
        }
        public SObJectResult() {
          
        }
    }
}

and then custom app in lightning, using this app we are passing data from LWC to Lightning component.

lwcMultiLokkupDemo.app

<lightning:card title="">
    <c:lwcMultiLookup objectName="Account" fieldName="Name" 
                      iconName = "standard:account" onselected="{!c.selectedRecords}"/>

    <div class="slds-page-header">
        <div class="slds-media">
            <div class="slds-media__figure">
                <span class="slds-icon_container slds-icon-standard-opportunity" title="Account Record">
                </span>
            </div>
            <div class="slds-media__body">
                <h1 class="slds-page-header__title slds-truncate slds-align-middle" title="Account Record">Accounts</h1>
                <p class="slds-text-body_small slds-line-height_reset"></p>
            </div>
        </div>
    </div>
    <table class="slds-table slds-table_bordered slds-table_cell-buffer">
        <thead>
            <tr class="slds-text-title_caps">
                <th scope="col">
                    <div class="slds-truncate" title="Account Id">Account Id</div>
                </th>
                <th scope="col">
                    <div class="slds-truncate" title="Account Name">Account Name</div>
                </th>
            </tr>
        </thead>
        <tbody>
            <aura:iteration var="selectRec" items="{!v.selectedRecords}">
                <tr>
                    <th scope="row" data-label="Account Id">
                        <div class="slds-truncate" title="{!selectRec.recId}"><a id="{!selectRec.recId}">{!selectRec.recId}</a></div>
                    </th>
                    <td data-label="Account Name">
                        <div class="slds-truncate" title="{!selectRec.recName}">{!selectRec.recName}</div>
                    </td>
                </tr>
            </aura:iteration>
        </tbody>
    </table>
</lightning:card>

lwcMultiLokkupDemo.js

({
    selectedRecords : function(component, event, helper) {
        var selectRecName = event.getParam('selRecords');
        if(selectRecName != undefined) {
            component.set("v.selectedRecords", selectRecName);
        }
    }
})

Here I have share complete code for Multi Select Custom Lookup LWC. Code is pretty simple and I have just modify the Lookup code. Now we are filtering the selected records in SOQL and passing a list of array in parent Lightning Component.

In this post we have also covered how to use wrapper in Lightning or Lightning Web Components.

Did you liked this post or have any suggestions, let me know in comments. Happy programming 🙂

Advertisements

Leave a Reply

This site uses Akismet to reduce spam. Learn how your comment data is processed.