html code

Configurable Record Picker In Lightning Web Component

Creating a configurable record picker in Lightning Web Component has been traditionally achieved through custom lookup components, like the Generic Multi-Select Lookup Component, for multi-record selection. While such components remain relevant for multiple-record selection, Salesforce introduced the lightning-record-picker control to simplify the selection of single records within custom LWC (Lightning Web Component) screens. This new control negates the need for custom components solely for record lookup. This guide focuses on crafting a configurable record picker in LWC, facilitating dynamic filter criteria and field adjustments at runtime without necessitating code modifications.

How does the Record Picker Control Operate?

Before employing this control, let’s delve into its internal workings. The Record Picker control utilizes a GraphQL Wire Adapter to conduct record searches, display them, and facilitate user selection. Its internal use of GraphQL enables us to apply record filtering and exhibit additional fields within the lookup.

Consider the following code snippet to display a Record Picker for the Account object.

<template>
    <lightning-card title="Record Picker">
        <lightning-record-picker
        label="Accounts"
        placeholder="Search Accounts..."
        object-api-name="Account">
        </lightning-record-picker>
    </lightning-card>
</template>

When the record picker is displayed on the page and a record is searched, it initiates a GraphQL API request. You can inspect the network tab in the browser debugger to observe the GraphQL request made for the record search. In the image below, two callouts highlight the GraphQL API call:

  • Callout 1: When performing a search in the record picker, it triggers a GraphQL request, adding the URL parameter “&aura.RecordUi.executeGraphQL=1”.
  • Callout 2: This represents the request made to the GraphQL API with the searched text.

On the basis of the searched text, the result is returned from Salesforce Object and shown in record picker control.

How do you use the Record Picker?

To employ this element, you require a minimum of two attributes: object-api-name, which specifies the object for displaying the record, and label, which serves as the caption or header text for the control.

<template>
    <lightning-card title="Record Picker">
        <lightning-record-picker
        label="Accounts"
        object-api-name="Account">
        </lightning-record-picker>
    </lightning-card>
</template>

This control has below important properties

matching-infoThis is field information that will show in the record picker. Like, show the name field for record selection.display-infoThis will show additional fields with the primary field (matching-info). Multiple additional fields can be shown. Like, show email and phone along with the primary name field.filterThis attribute is used to filter the record picker. Like, show only USA records

Create a Configurable Record Picker Component

The Record Picker component suits simple applications well. However, for more control over record selection, customization becomes necessary.

While all attributes can be customized, I focused on modifying three attributes—matching-info, display-info, and filter. To allow for customization, I introduced two custom metadata types.

The Record Picker Config custom metadata type will contain object and field details displayed in the Record Picker. You’ll need to create custom fields based on the images below within this metadata type.

Add records in this metadata object.

Developer NameDisplay Field NameDisplay Secondary FieldsObject API
Account_Picker_On_Patient_PageNameEmail__c, PersonPhoneAccount

We can include multiple additional fields by adding them in a comma-separated format within the ‘Display Secondary Fields’ field.

The ‘Field Condition Operator’ list comprises operators utilized with the filter field. It’s necessary for GraphQL to conduct searches using filter criteria. Input these values within the Field Condition Operator picklist.

Record Picker Condition Operator - SalesforceCodex

Add records in this metadata object.

Record Picker ConfigCondition FieldCondition OperatorCondition ValueAccount_Picker_On_Patient_PageNameLikea%

We are ready with configuration object creation. We also created configuration records.

Apex Class

We have to develop an Apex class responsible for retrieving configuration records from the custom metadata type, considering the provided configuration name.

public class RecordPickerController {
    @AuraEnabled(cacheable=true)
    public static RecordPickerDTO.ObjectInfo getRecordPicker(string metadataName){
        return RecordPickerService.getRecordPicker(metadataName);
    }
}
public class RecordPickerDTO {
	public class ObjectInfo{
        @auraenabled
        public string ObjectName {get;set;}
        @auraenabled
        public string PrimaryField {get;set;}
        @auraenabled  
        public string SecondaryFields {get;set;}
        @auraenabled
        public List<FieldCondition> Conditions {get;set;}
    }
    public class FieldCondition{
        @auraenabled
        public string FieldName {get;set;}
        @auraenabled
        public string Condition {get;set;}
        @auraenabled
        public string ConditionValue {get;set;}
        @auraenabled
        public boolean IsLiteral {get;set;}
        @auraenabled
        public boolean IsDynamicValue {get;set;}        
    }
}
public class RecordPickerSelector {
    //Retrieve Custom Metadata Records
    public static RecordPickerConfig__mdt getMetadataConfig(string metadataName){
     	return [SELECT Id, ObjectAPI__c, DisplayFieldName__c, DisplaySecondaryFields__c, 
                (SELECT Id, RecordPickerConfig__c, ConditionFieldAPI__c, Condition__c, ConditionValue__c, IsLiteral__c, IsDynamic__c 
                 FROM Record_Picker_Condition_Configs__r)
                                     FROM RecordPickerConfig__mdt where DeveloperName=:metadataName];   
    }
}
public class RecordPickerService {
    //Get Record Picker Setting for provided configuration
	public static RecordPickerDTO.ObjectInfo getRecordPicker(string metadataName){
        RecordPickerConfig__mdt mdt=RecordPickerSelector.getMetadataConfig(metadataName);
        RecordPickerDTO.ObjectInfo objDto=new RecordPickerDTO.ObjectInfo();
        objDto.ObjectName=mdt.ObjectAPI__c;
        objDto.PrimaryField=mdt.DisplayFieldName__c;
        objDto.SecondaryFields=mdt.DisplaySecondaryFields__c;
        
        //Loop all condition for record picker
        List<RecordPickerDTO.FieldCondition> fields=new List<RecordPickerDTO.FieldCondition>();
        for(RecordPickerConditionConfig__mdt cm : mdt.getSObjects('Record_Picker_Condition_Configs__r')) {
            RecordPickerDTO.FieldCondition fCondition=new RecordPickerDTO.FieldCondition();
            fCondition.FieldName=String.valueOf(cm.get('ConditionFieldAPI__c'));
            fCondition.Condition=String.valueOf(cm.get('Condition__c'));
            fCondition.ConditionValue=String.valueOf(cm.get('ConditionValue__c'));
            fCondition.IsLiteral=Boolean.valueOf(cm.get('IsLiteral__c'));
            fCondition.IsDynamicValue=Boolean.valueOf(cm.get('IsDynamic__c'));
        	fields.add(fCondition);
    	}
       	objDto.Conditions=fields;
        return objDto;
    }
}

Let’s craft a Lightning Web Component to create a Configurable Record Picker. This component will utilize the RecordPickerController apex class to fetch the record picker configuration and set the properties of the lightning-record-picker control based on the retrieved configuration.

<template>
    <template lwc:if={config}>
        <lightning-record-picker
        label={label}
        placeholder={placeHolder}
        object-api-name={config.ObjectName}
        matching-info={matchingInfo} 
        display-info={displayInfo}
        filter={filter}>
        </lightning-record-picker>
    </template>
</template>
import { LightningElement,api,wire,track } from 'lwc';
import getRecordPicker from '@salesforce/apex/RecordPickerController.getRecordPicker';
export default class ObjectRecordPicker extends LightningElement {
    @api recordPickerConfigName;
    @api label='Account';
    @api placeHolder='Select...';
    config=undefined;
    @track matchingInfo;
    @track displayInfo;
    @track filter;
    @wire(getRecordPicker, {metadataName:'$recordPickerConfigName'})
    wiredConfigs({ error, data }) {
    if (data) {
        this.config = data;
        this.error = undefined;
        this.setCriteria();
        this.setFields();
      } else if (error) {
        this.error = error;
        this.config = undefined;
      }
    }
    //Set Primary and Additional Fields
    setFields(){
        if(this.config){
            this.matchingInfo = {
                primaryField: { fieldPath: this.config.PrimaryField }
            }
            if(this.config.SecondaryFields){
                var secondFields=this.config.SecondaryFields.split(',');
                var dispFields=[];
                var fldsNames=[];
                for(var cg of secondFields){
                    dispFields.push({ fieldPath: cg});
                    fldsNames.push(cg);
                }
                this.matchingInfo.additionalFields=dispFields;
                this.displayInfo={additionalFields:fldsNames};
            }
        }
    }
    //Set Filter Criteria
    setCriteria(){
        var fltrs=[];
        if(this.config.Conditions)
        {
            for(var cg of this.config.Conditions){
                fltrs.push(
                    {
                        fieldPath: cg.FieldName,
                        operator: cg.Condition,
                        value: cg.ConditionValue,
                    },
                );
            }
            if(fltrs.length>0){
                this.filter = {
                    criteria: fltrs
                };
            }
        }
    }
}
<?xml version="1.0" encoding="UTF-8"?>
<LightningComponentBundle xmlns="http://soap.sforce.com/2006/04/metadata">
    <apiVersion>58.0</apiVersion>
    <isExposed>true</isExposed>
    <masterLabel>Object Record Picker</masterLabel>
    <targets>
        <target>lightningCommunity__Page</target>
        <target>lightningCommunity__Default</target>
        <target>lightning__RecordPage</target>
        <target>lightning__AppPage</target>
        <target>lightning__HomePage</target>
        <target>lightning__Tab</target>
    </targets>
    <targetConfigs>
        <targetConfig targets="lightning__RecordPage">
            <property name="recordPickerConfigName" label="Record Picker Config Name" type="String" />
            <property name="label" label="Record Picker Label" type="String" />
            <property name="placeHolder" label="Record Picker Place Holder"  type="String" />
        </targetConfig>
    </targetConfigs>
</LightningComponentBundle>

The component is set up for direct use on the record page, but it can also be employed within other LWC components. In the code below, “Account_Picker_On_Patient_Page” refers to the name of the record picker configuration record.

<c-object-record-picker record-picker-config-name='Account_Picker_On_Patient_Page' label='Account' place-holder='Select Account'></c-object-record-picker>

I haven’t included the configuration code for literal values. The “Is Literal” field can be utilized to set literal values. If you require assistance with this configuration, let’s connect.

Use Created Component in Record Page

Record Picker in Record Page - SalesforceCodex