Posted in

custom reusable lookup in lwc using sosl

Hey there,

Welcome back 🙂 . Here in this blog post, we are going to develop a custom reusable lookup using SOSL.

Step 1 – Create ‘lwcsearchcomponent‘ component and use below code

lwcsearchcomponent.html

<template>
    <lightning-input 
        type="search" 
        value={searckKeyword}
        onchange={handleChange}
        label={searchLabel}
    > </lightning-input>
</template>

lwcsearchcomponent.js

import { LightningElement, api, track } from 'lwc';

export default class Lwcsearchcomponent extends LightningElement {

    @track searckKeyword;
    @api isrequired = 'false';
    @api searchLabel = 'Search Account';
    @api showLabel   = 'true';

    /* Check the isrequired prop is true then set the prop to true*/
    renderedCallback() {
        if ( this.isrequired === "false" )
            return;
        if ( this.isrequired === "true") {
            let picklistInfo = this.template.querySelector('lightning-input');
            picklistInfo.required = true;
            this.isrequired = "false";
        }
        
    }

    handleChange(event) {
        var keyword = event.target.value;
        /* Create & dispatch the event to parent component with the search keyword */
        if ( keyword && keyword.length >= 2 ) {
            let searchEvent = new CustomEvent('search',{
                detail : { value : keyword }
            });
            this.dispatchEvent(searchEvent);
        }
        
    }
}

Step 2 – Create ‘lwcrecordlist‘ component and use below code.

lwcrecordlist.html

<template>
    <li role="presentation" class="slds-listbox__item slds-p-top_small" onclick={handleSelect}>
        <span id="listbox-option-unique-id-01"
            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" title="Icon">
                    <lightning-icon icon-name={iconname} size="small"></lightning-icon>
                    <span class="slds-assistive-text">Icon</span>
                </span>
            </span>
            <span class="slds-media__body">
                <span class="slds-listbox__option-text slds-listbox__option-text_entity">{rec.Name}</span>
            </span>
        </span>
    </li>
</template>

lwcrecordlist.js

import { LightningElement, api } from 'lwc';

export default class Lwcrecordlist extends LightningElement {
    /* Public Property to pass the single record & iconname */
    @api rec;
    @api iconname = 'standard:account';

    handleSelect(  ) {
        let selectEvent = new CustomEvent('select',{
            detail : { selRec : this.rec }
        });
        this.dispatchEvent( selectEvent );
    }

    handleRemove(  ) {
        let selectEvent = new CustomEvent('select',{
            detail : { selRec : undefined }
        });
        this.dispatchEvent( selectEvent );
    }
}

Step 3 – create ‘CustomSearchController‘ apex class & use below code

CustomSearchController.apxc

public with sharing class CustomSearchController {
    
    /* Create an Aura Enabled Method which tooks objectName, fieldtoSearch and the text to search */
    /* Develop the Dynamic SOSL and then use Query method of Search Class to return the result */
    @AuraEnabled
    public static String searchRecords(String objName, String fieldName, 
                                     String searchKey){
        String searchKeyword = searchKey + '*';
        String returningQuery = objName+' ( Id, '+fieldName+')';
        String query = 'FIND :searchKeyword IN ALL FIELDS RETURNING '+returningQuery+' LIMIT 2000';
        List<List<sObject>> sobjectList = Search.query(Query);
        return JSON.serialize(sobjectList);
    }
}

Step 4 – Create ‘customlwclookup‘ component & use below code

customlwclookup.html

<template>
    <div class="slds-m-padding_around">
        <template if:false={selectedRecord} >
            <c-lwcsearchcomponent onsearch={hanldeSearch} search-label={label}
                isrequired="true" ></c-lwcsearchcomponent>
        </template>
    </div>
    <div class="slds-m-padding_around">
        <template if:false={selectedRecord} >
            <template if:true={records}>
                <template for:each={records} for:item="rec" for:index="index">
                    <ul key={rec.Id} 
                        class="slds-listbox " >
                    <c-lwcrecordlist key={rec.Id} rec={rec}
                         iconname={iconname}
                         onselect={handleSelect}>
                    </c-lwcrecordlist>
                    </ul>
                </template>
            </template>
        </template>
        <template if:true={selectedRecord} >
            <label class="slds-form-element__label" for="unique-id-of-input">
                    {label}
            </label>
            <div class="slds-pill-container">
                <lightning-pill class="pillSize" 
                        href="JavaScript:void(0);"
                        label={selectedRecord.Name} 
                        name={selectedRecord.Name} 
                        onremove={handleRemove}>
                    <lightning-icon icon-name={iconname} variant="circle"  
                            alternative-text={objectName}></lightning-icon>        
                </lightning-pill>
            </div>
        </template>
    </div>
</template>

customlwclookup.js

This component is required 4 public property to work the lookup for any object.

  1. objectName
  2. fieldName
  3. iconname
  4. label
  5. parentidfield

See the comments for more information

import { LightningElement, api, track } from 'lwc';
import searchRecords from '@salesforce/apex/CustomSearchController.searchRecords';
export default class Customlwclookup extends LightningElement {

    /* public property */
    /* these public property will be used when using this component inside other component for the lookup functionality */
    /* objectName is the name of the Object which is parent either master-detail or lookup */
    /* fieldName is the field of parent object in which text needs to be searched */
    /* iconname - icon to display in the list and after selection of the record */
    /* label - to show the label for the lookup */
    /* parentidfield - the apiname of lookup/matser-detail in the child object this field is useful to indentify which parent record has been select if there are multiple lookup for a single child record */
    @api objectName = 'Account';
    @api fieldName  = 'Name';
    @api iconname   = 'standard:record';
    @api label      = 'Account';
    @api parentidfield = 'AccountId';

    /* private property */
    @track records;
    @track selectedRecord;

    hanldeSearch(event) {

        var searchVal = event.detail.value;

        searchRecords({
            objName   : this.objectName,
            fieldName : this.fieldName,
            searchKey : searchVal
        })
        .then( data => {
            if ( data ) {
                let parsedResponse = JSON.parse(data);
                let searchRecordList = parsedResponse[0];
                for ( let i=0; i < searchRecordList.length; i++ ) {
                      let record = searchRecordList[i];
                      record.Name = record[this.fieldName];
                }
                //window.console.log(' data ', searchRecordList);
                this.records = searchRecordList;
            }
        })
        .catch( error => {
            window.console.log(' error ', error);
        });
    }

    handleSelect(event) {
        var selectedVal = event.detail.selRec;
        this.selectedRecord =  selectedVal;
        let finalRecEvent = new CustomEvent('select',{
            detail : { selectedRecordId : this.selectedRecord.Id, parentfield : this.parentidfield }
        });
        this.dispatchEvent(finalRecEvent);
    } 

    handleRemove() {
        this.selectedRecord =  undefined;
        this.records = undefined;
        let finalRecEvent = new CustomEvent('select',{
            detail : { selectedRecordId : undefined, parentfield : this.parentidfield }
        });
        this.dispatchEvent(finalRecEvent);
    }
    
}

customlwclookup.css

.pillSize{
    width: 100%;
}

Step 5 – Test the component

Create another component and use the below code for the same. In the below example, I have used the customlwclookup component 3 times. to test the functionality for Account, Case & Contact Object.

<template>
    <lightning-card title="Lookup Demo" icon-name="standard:record">
        <div class="slds-p-around_small">
            <c-customlwclookup object-name="Account" field-name="Name"
                label="Account" parentidfield="AccountId"
                iconname="standard:account" ></c-customlwclookup>
        </div>

        <div class="slds-p-around_small">
                <c-customlwclookup object-name="Case" field-name="Subject"
                    label="Case" parentidfield="Case__c"
                    iconname="standard:case" ></c-customlwclookup>
        </div>

        <div class="slds-p-around_small">
                <c-customlwclookup object-name="Contact" field-name="Name"
                    label="Contact" parentidfield="ContactId"
                    iconname="standard:contact" ></c-customlwclookup>
        </div>
    </lightning-card>
</template>

Use below code for .xml file & after deploying the code into org. You can add this component inside home/record/app page and test the functionality

<?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__HomePage</target>
        <target>lightning__RecordPage</target>
        <target>lightning__Tab</target>
    </targets>
</LightningComponentBundle>

Happy Learning 🙂 Keep Sharing 😉

#Salesforce #Trainhead #AskPanther #BeASalesforceChamp

Amit Singh aka @sfdcpanther/pantherschools, a Salesforce Technical Architect, Consultant with over 8+ years of experience in Salesforce technology. 21x Certified. Blogger, Speaker, and Instructor. DevSecOps Champion

2 thoughts on “custom reusable lookup in lwc using sosl

Comments are closed.

Discover more from Panther Schools

Subscribe now to keep reading and get access to the full archive.

Continue reading