Hi Developer, As we all know that LWC is a complete new way to develop the Lightning component and there are very limited no of resources to learn LWC.

So, here is this tutorial we are going to learn how we can create a Custom Reusable Lookup based on user input.

Setp1:- Create searchComponent

This component is the one, who enables the search functionality. Use the below code for HTML markup and JavaScript.

<template>
    <div class="slds-grid slds-wrap">
        <div class="slds-col slds-size_4-of-4">
            <div>
                <!-- Create an Input Field where user can enter text to find the
                Records-->
                <lightning-input variant="label-hidden" 
                    label="Search Record" value={searchKey} type="search"
                    onchange={handleChange} placeholder="type text here">
                </lightning-input>
            </div>
        </div>
    </div>
</template>

searchComponent.js

import { LightningElement, track } from 'lwc';

export default class SearchComponent extends LightningElement {
    
    @track searchKey;
    handleChange(event){
        /* eslint-disable no-console */
        //console.log('Search Event Started ');
        const searchKey = event.target.value;
        /* eslint-disable no-console */
        event.preventDefault();
        const searchEvent = new CustomEvent(
            'change', 
            { 
                detail : searchKey
            }
        );
        this.dispatchEvent(searchEvent);
    }
}

Step2: – Create recordList component

In this component, we will display the list of all the records which will be returned matching with the entered text. Here is the code for HTML markup & JavaScript Class.

<template>
    <!--<a href="JavaScript:Void(0)" style="text-decoration:none;" onclick={handleSelect}>
        <lightning-layout>
            <lightning-layout-item>
                <lightning-icon icon-name={iconname} size="small"></lightning-icon>
                  
            </lightning-layout-item>
            <lightning-layout-item>
                {record.Name}
            </lightning-layout-item>
        </lightning-layout>
    </a> -->
    <div >
        <div class="slds-grid slds-wrap 
                        slds-dropdown_length-with-icon-7 
                        slds-dropdown_fluid
                        slds-p-left_small"
                 >
                <div class="slds-col slds-size_4-of-4 ">
                    <ul class="slds-listbox slds-listbox_vertical" role="presentation">
                        <li role="presentation" class="slds-listbox__item">
                            <div class="slds-media slds-listbox__option 
                                                        slds-listbox__option_entity 
                                                        slds-listbox__option_has-meta" 
                                                        role="option"
                                onclick={handleSelect}>
                                <span class="slds-media__figure slds-listbox__option-icon">
                                    <lightning-icon icon-name={iconname} size="small"></lightning-icon>
                                </span>
                                <span class="slds-media__body" 
                                    style="padding-top: 9px;font-weight: 600;">
                                    <span class="slds-listbox__option-text 
                                                                 slds-listbox__option-text_entity">
                                        {record.Name}
                                    </span>
                                </span>
                            </div>
                        </li>
                    </ul>
                </div>
        </div>
    </div>
</template>

recordList.js

import { LightningElement, api } from 'lwc';

export default class RecordList extends LightningElement {
    @api record;
    @api fieldname;
    @api iconname;

    handleSelect(event){
        event.preventDefault();
        const selectedRecord = new CustomEvent(
            "select",
            {
                detail : this.record.Id
            }
        );
        /* eslint-disable no-console */
        //console.log( this.record.Id);
        /* fire the event to be handled on the Parent Component */
        this.dispatchEvent(selectedRecord);
    }
}

Step3: – Create customLookup Component

Main component which will contain both the component searchComponent and recordList component and also, responsible for calling the apex method.

<template>
    <template if:false={selectedRecord}>
        <div class="slds-p-around_x-small">
            <c-search-component 
                onchange={handleOnchange}>
            </c-search-component>
        </div>
    </template>
    <div >
        <template if:true={error}>
            <template if:true={error.details}>
                <template if:true={error.details.body}>
                    {error.details.body.message}
                </template>
            </template>
        </template>
    </div>
    <div>
        <template if:false={selectedRecord}>
            <template if:true={records}>
                <template for:each={records} for:item="record">
                    <c-record-list key={record.Id} record={record} 
                        onselect={handleSelect} iconname={iconname}
                        fieldname={searchfield}>
                    </c-record-list>
                </template>
            </template>
        </template>
        <template if:false={selectedRecord}>
        </template>
    </div>
    <div class="slds-p-around_x-small">
        <template if:true={selectedRecord}>
            <div class="slds-combobox__form-element slds-input-has-icon 
                            slds-input-has-icon_left-right" role="none">
                    <span class="slds-icon_container
                                slds-icon-standard-account 
                                slds-combobox__input-entity-icon" title="Account">
                        <lightning-icon icon-name={iconname} ></lightning-icon>
                    </span>
                    <input class="slds-input slds-combobox__input
                           slds-combobox__input-value" 
                           id="combobox-id-5" aria-controls="listbox-id-5" 
                           autocomplete="off" role="textbox" type="text" 
                           placeholder="Select an Option" readonly=""
                           value={selectedRecord.Name}
                           disabled
                           />
                    <button class="sicon_container slds-button slds-button_icon 
                                   slds-input__icon slds-input__icon_right" 
                            title="Remove selected option"
                            onclick={handleRemove}>
                        <lightning-icon icon-name="utility:close" size="small">

                        </lightning-icon>
                        <span class="slds-assistive-text">Remove selected option</span>
                    </button>
                </div>
            <!--<lightning-layout>
                <lightning-layout-item>
                    <lightning-pill label={selectedRecord.Name} onremove={handleRemove}>
                        <lightning-icon icon-name={iconname}></lightning-icon>
                    </lightning-pill>
                </lightning-layout-item>
            </lightning-layout> -->
        </template>
    </div>
</template>

customLookup.js

import { LightningElement, track, api } from 'lwc';
import findRecords from '@salesforce/apex/CustomLookupController.findRecords';
export default class CustomLookup extends LightningElement {
    @track records;
    @track error;
    @track selectedRecord;
    @api index;
    @api relationshipfield;
    @api iconname = "standard:account";
    @api objectName = 'Account';
    @api searchfield = 'Name';

    /*constructor(){
        super();
        this.iconname = "standard:account";
        this.objectName = 'Account';
        this.searchField = 'Name';
    }*/

    handleOnchange(event){
        //event.preventDefault();
        const searchKey = event.detail.value;
        //this.records = null;
        /* eslint-disable no-console */
        //console.log(searchKey);

        /* Call the Salesforce Apex class method to find the Records */
        findRecords({
            searchKey : searchKey, 
            objectName : this.objectName, 
            searchField : this.searchfield
        })
        .then(result => {
            this.records = result;
            for(let i=0; i < this.records.length; i++){
                const rec = this.records[i];
                this.records[i].Name = rec[this.searchfield];
            }
            this.error = undefined;
            //console.log(' records ', this.records);
        })
        .catch(error => {
            this.error = error;
            this.records = undefined;
        });
    }
    handleSelect(event){
        const selectedRecordId = event.detail;
        /* eslint-disable no-console*/
        this.selectedRecord = this.records.find( record => record.Id === selectedRecordId);
        /* fire the event with the value of RecordId for the Selected RecordId */
        const selectedRecordEvent = new CustomEvent(
            "selectedrec",
            {
                //detail : selectedRecordId
                detail : { recordId : selectedRecordId, index : this.index, relationshipfield : this.relationshipfield}
            }
        );
        this.dispatchEvent(selectedRecordEvent);
    }

    handleRemove(event){
        event.preventDefault();
        this.selectedRecord = undefined;
        this.records = undefined;
        this.error = undefined;
        /* fire the event with the value of undefined for the Selected RecordId */
        const selectedRecordEvent = new CustomEvent(
            "selectedrec",
            {
                detail : { recordId : undefined, index : this.index, relationshipfield : this.relationshipfield}
            }
        );
        this.dispatchEvent(selectedRecordEvent);
    }


}

Step4 :- Create Demo App and test lookup

<aura:application extends="force:slds">
    <c:customLookup iconname="standard:case" 
                    objectName="Case"
                    searchfield="CaseNumber"/>
</aura:application>	

If you have any Queries or Suggestions DM me @cloudyamit or email me @ sfdcpanther@gmail.com

Happy Learning  🙂 😉

#SFDCPanther #Trailblazer

2 thoughts on “Custom Reusable Lookup in LWC

Leave a Reply

Your email address will not be published. Required fields are marked *