How to create a reusable Custom Lookup In Lightning Web Component Using SOSL?

on

|

views

and

comments

Hello Dear #Trailblazers,

In this blog post, we are doing to learn how we can create reusable Custom Lookup using Lightning Web Component and we will use SOSL to develop the Lightning Web Component

Features

  1. Custom Lookup for All Stadard, Custom and External Object
  2. Ability to Create a New Record from the Lookup Component itself
  3. Ability to pass the pre selected record Id and Name
  4. Ability to use under Iteration in a Custom Table or any custom development
  5. Displays Recently Viewed Record when focus is on input

Step1 – Create an Apex Class and name it “SearchController”

This class will have a method to search the records and return the List<List<sObject>> here is the code for the same

/**
 * @description       :
 * @author            : Amit Singh
 * @group             :
 * @last modified on  : 12-21-2021
 * @last modified by  : Amit Singh
**/
public with sharing class SearchController {
    @AuraEnabled
    public static List<sObject> search(String objectName, List<String> fields, String searchTerm){
        String searchKeyword = searchTerm + '*';
        String returningQuery = '';
        returningQuery = objectName+' ( Id, '+String.join(fields,',')+')';
        String query = 'FIND :searchKeyword IN ALL FIELDS RETURNING '+returningQuery+' LIMIT 20';
        List<List<sObject>> searchRecords = new List<List<sObject>>();
        List<SObject> sobjList = new List<SObject>();
        if(String.isBlank(searchTerm)){
            String soqlQuery = 'SELECT Id, Name, Type, LastViewedDate FROM RecentlyViewed WHERE Type =\''+objectName+'\' ORDER BY LastViewedDate DESC LIMIT 5';
            sobjList = Database.query( soqlQuery );
            searchRecords.add(sobjList);
        }else{
            searchRecords = Search.Query(Query);
        }
        return searchRecords.get(0);
    }

    @AuraEnabled
    public static sObject getRecentlyCreatedRecord(String recordId, List<String> fields, String objectName){
        sObject createdRecord;
        try {
            String query = 'SELECT Id, '+String.join(fields,',')+' FROM '+objectName+' WHERE Id = \''+recordId+'\'';
            List<SObject> sobjList = Database.query( query );
            createdRecord = sobjList.get(0);
        } catch (Exception e) {
            throw new AuraHandledException(e.getMessage());
        }
        return createdRecord;
    }
}
/**
 * @description       : 
 * @author            : Amit Singh
 * @group             : 
 * @last modified on  : 12-29-2021
 * @last modified by  : Amit Singh
**/
@IsTest
public with sharing class SearchControllerTest {

    @IsTest
    public static void searchTest(){
        Account accuntRecord = createAccountRecord();
        List<String> fields = new List<String>();
        fields.add('Name');
        fields.add('Phone');
        fields.add('Rating');
        List<String> searchResultsIds = new List<String>();
        searchResultsIds.add(accuntRecord.Id);
        Test.startTest();
        Test.setFixedSearchResults(searchResultsIds);
        SearchController.search('Account', fields, 'Salesforce');
        Test.stopTest();
    }

    @IsTest
    public static void searchTest1(){
        Account accuntRecord = createAccountRecord();
        List<String> fields = new List<String>();
        fields.add('Name');
        fields.add('Phone');
        fields.add('Rating');
        List<String> searchResultsIds = new List<String>();
        searchResultsIds.add(accuntRecord.Id);
        Test.startTest();
        Test.setFixedSearchResults(searchResultsIds);
        SearchController.search('Account', fields, '');
        Test.stopTest();
    }

    @IsTest
    public static void getRecentlyCreatedRecordTest(){
        Account accuntRecord = createAccountRecord();
        List<String> fields = new List<String>();
        fields.add('Name');
        fields.add('Phone');
        fields.add('Rating');
        String accountId = accuntRecord.Id;
        Test.startTest();
        SObject account = SearchController.getRecentlyCreatedRecord( accountId , fields, 'Account');
        String fetchedAccountId = (String)account.get('Id');
        System.assertEquals( fetchedAccountId , accountId , 'Id is not matching' );
        Test.stopTest();
    }

    private static Account createAccountRecord(){
        Account acc = new Account();
        acc.Name = 'Salesforce.com';
        acc.Rating = 'Hot';
        acc.Industry = 'Technology';
        acc.Description = 'This is a test account';
        acc.BillingCity = 'San Francisco';
        acc.BillingState = 'CA';
        acc.BillingPostalCode = '94105';
        acc.BillingCountry = 'USA';
        acc.Phone = '4158889999';
        acc.Type = 'Customer';
        insert acc;
        return acc;
    }
}

Step2 Create a Lightning Web Component

  1. selectedRecord Component – First, we need to create a Child Component that will display the selected record in the lookup component.

Create an LWC Component and name it selectedRecord and use the code from the below files

2. searchComponent

This is the main component that will have complete functionality for the lookup. This component has below main public property which is important to use

  1. valueId; – This field holds the Selected Record Id if the parent record is already there
  2. valueName; – This field holds the Selected Record Name if the parent record is already there
  3. objName= ‘Account’; – The Parent Object API Name
  4. iconName= ‘standard:account’; – The Icon which you wanted to display
  5. labelName; – The Label for the Search
  6. currentRecordId; – The child record Id if applicable
  7. placeholder= ‘Search’; – Search Place holder
  8. fields= [‘Name’]; – The Fields that You wanted to Query
  9. displayFields= ‘Name, Rating, AccountNumber’; – The Fields that You wanted to use in the Lookup
  10. onlookup – the custom event which holds the selected record, SelectedRecordId & the child recorded if applicable
  11. createRecord – This variable accepts the boolean value that controls either to display the new button in the list or Not.
  12. recordTypeId – Id of the Record Type if need to create a new Record.
  13. fieldsToCreate – Accepts the list of fields which needs to be displayed on New Record Form
  14. index – The Row no if the Lookup component is used inside the Custom data tables

Usage

Below is the code on how you can use this component inside your parent component.

<c-search-component
                obj-name={typeAttributes.object}
                icon-name={typeAttributes.icon}
                label-name={typeAttributes.label}
                placeholder={typeAttributes.placeholder} 
                fields={typeAttributes.fields}
                display-fields={typeAttributes.displayFields}
                value-id={typeAttributes.valueId}
                value-name={typeAttributes.valueName}
                onlookup={handleLookup}
                fields-to-create={fieldsToCreate} 
                index={index}
                create-record=false
                current-record-id={typeAttributes.currentRecordId} >
</c-search-component>

You can find the complete Code here

Step3 – Demo Time

Create a Lightning Web Component and use the SearchComponent that you have created

<!--
    @description       : 
    @author            : Amit Singh
    @group             : 
    @last modified on  : 03-24-2021
    @last modified by  : Amit Singh
    Modifications Log 
    Ver   Date         Author       Modification
    1.0   03-24-2021   Amit Singh   Initial Version
-->
<template>
    <lightning-card  variant="Narrow"  title="Custom Lookup" icon-name="standard:account">
        <p class="slds-p-horizontal_small">
            <c-search-component
                obj-name="Contact"
                icon-name="standard:contact"
                label-name="Contact"
                placeholder="Search" 
                fields={fields}
                display-fields={displayFields}
                onlookup={handleLookup} >
            </c-search-component>
        </p>
        
    </lightning-card>
</template>
/**
 * @description       : 
 * @author            : Amit Singh
 * @group             : 
 * @last modified on  : 03-24-2021
 * @last modified by  : Amit Singh
 * Modifications Log 
 * Ver   Date         Author       Modification
 * 1.0   03-24-2021   Amit Singh   Initial Version
**/
import { LightningElement } from 'lwc';

export default class CustomLookup extends LightningElement {
    fields = ["Name","Email","Phone"];
    displayFields = 'Name, Email, Phone'

    handleLookup(event){
        console.log( JSON.stringify ( event.detail) )
    }
}

Once you select any record below is the JSON that you get using event.detail

{
  "data": {
    "record": {
      "Id": "0034x000004r7FvAAI",
      "Name": "Ashley James",
      "Email": "ajames@uog.com",
      "Phone": "+44 191 4956203",
      "FIELD1": "Ashley James",
      "FIELD2": "ajames@uog.com",
      "FIELD3": "+44 191 4956203"
    },
    "recordId": "0034x000004r7FvAAI"
  }
}

Thanks for reading 🙂

#Salesforce #DeveloperGeeks #Trailblazer

Please do like share subscribe to the blog post and YouTube channel.

Amit Singh
Amit Singhhttps://www.pantherschools.com/
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
Share this

Leave a review

Excellent

SUBSCRIBE-US

Book a 1:1 Call

Must-read

How to start your AI Journey?

Table of Contents Introduction Are you tired of the same old world? Do you dream of painting landscapes with your code, composing symphonies with data, or...

The Secret Weapon: Prompt Engineering: 🪄

Table of Contents Introduction Crafting the perfect prompt is like whispering secret instructions to your AI muse. But there's no one-size-fits-all approach! Exploring different types of...

How to Singup for your own Production org?

Let's see how we can have our salesforce enterprise Salesforce Org for a 30-day Trial and use it as a Production environment. With the...

Recent articles

More like this

29 COMMENTS

  1. Hi Amit,

    This is awesome. Thank you very much. I recently purchased your Udemy course and I just love it. Just a quick question.

    How can I prepopulate a record in the Search component? For example I’m using the Search component inside another component and if a certain account exists in the org I want to have it selected when I launch the component otherwise I want to be able to search for an account. Is that possible?

    Thanks in advance.

  2. Hi Amit, while using custom object(__c), I am getting error as undefined property to lowercase. Can u pls provide custom object with custom fields code in the same way.Thanks

  3. Hi Thanku so much, but if we are removing one selected record and typing another input..getting error as record id not defined. Please help

  4. Hi Amit,

    Using this inside a for:each, whenever I try to open the Lookup component on a specific record, it opens the component in all of the records of the for:each record List.

    Do you know how can this be avoided?

    Thank you

  5. This was awesome – thank you so much.
    Do you possibly have the test class you used for the Search Component? I’m fairly new to dev and I cannot get my test to pass so this would be a good learning opportunity for me if you could post it

  6. how can I create a table with lookfield list at 1 column and 2 column with checkbox. Want to create a record . please help

  7. When I’m using this inside an Aura component the dropdown doesn’t close when clicked outside. Can you tell me how to fix this?

LEAVE A REPLY

Please enter your comment!
Please enter your name here

5/5

Stuck in coding limbo?

Our courses unlock your tech potential