SFDC Stop - Always the latest about Salesforce


Full Tutorial Series with videos, free apps, live sessions, salesforce consulting and much more.


Telegram logo   Join our Telegram Channel

Sunday 31 December 2023

LWC Lookup Component by Salesforce: Lightning Record Picker

Hello Trailblazers,


In this post, we're going to learn about lightning-record-picker which is basically an input field using which you can search for salesforce records. The basic code to implement the same is provided below:

<template>
    <lightning-card hide-header label="Account Record Picker Card">
        <p class="slds-var-p-horizontal_small">
            <lightning-record-picker
                label="Select Account"
                placeholder="Type Something..."
                object-api-name="Account"
            ></lightning-record-picker>
        </p>
    </lightning-card>
</template>


As you can see above, I used the lightning-record-picker tag where I've setup the label as Select Account, the placeholder is Type Something... and the object-api-name is Account. You can ignore the lightning-card. I've added that only for a good white background as we're going to embed this component in our homepage. The result is shown below:



We also did common changes in our meta.xml file to embed this component in our homepage as shown below:

<?xml version="1.0" encoding="UTF-8"?>
<LightningComponentBundle xmlns="http://soap.sforce.com/2006/04/metadata">
    <apiVersion>55.0</apiVersion>
    <isExposed>true</isExposed>
    <masterLabel>Record Picker Demo</masterLabel>
    <targets>
        <target>lightning__AppPage</target>
        <target>lightning__RecordPage</target>
        <target>lightning__HomePage</target>
    </targets>
</LightningComponentBundle>

Now, it's time to do some more changes. Let's begin!

Add filter to our lookup component

Let's add a default filter to our record picker component such that it'll search only those accounts whose Rating is equal to Warm. It's time to update our js file now:

import { LightningElement } from 'lwc';

export default class RecordPickerDemo extends LightningElement {

    filter = {
        criteria: [
            {
                fieldPath: 'Rating',
                operator: 'eq',
                value: 'Warm'
            }
        ]
    };

}

As you can see above, we defined a filter object that consist of a single property named criteria. This property is an array which can have multiple objects, each having 3 properties:


1. fieldPath: API name of the field for the current object on which we've our record picker. You can also mention relationships upto one level, for example: Parent.Rating (considering the account object)


2. operator: It can have different values depending upon the comparison we want to perform. The possible values are given below:


eq = Equal

ne = Not Equal

lt = Less Than

gt = Greater Than

lte = Less than or equal

gte = Greater than or equal

in = Similar to IN operator of SOQL

nin = Similar to NOT IN operator of SOQL

like = Similar to LIKE operator of SOQL

includes = Check the result should include provided values

excludes = Check the result should exclude provided values


Different keywords provided above are applicable for fields of different data types. The fields and the operator values they support are provided in the salesforce documentation here. If you want to learn more about the keywords, you can check them in the GraphQL documentation here


3. value: Value for the applied filter


The updated html code to apply the filter we defined in js is provided below:

<template>
    <lightning-card hide-header label="Account Record Picker Card">
        <p class="slds-var-p-horizontal_small">
            <lightning-record-picker
                label="Select Account"
                placeholder="Type Something..."
                object-api-name="Account"
                filter={filter}
            ></lightning-record-picker>
        </p>
    </lightning-card>
</template>

Notice that we've populated filter property of our lightning-record-picker with the filter variable that is defined in our js.

With this Rating filter applied by default, we can only see a subset of records. As you can see below, only 4 account records are present in my org with Rating as Warm

If I search in my lookup now, the search is performed with this predefined Rating filter already applied to my record picker:


As you can see above, only these 4 records are visible as I search with keyword o

We can also specify a filterLogic property in our filter object. This property basically consist of logic to combine multiple filter criterias. For example: If in the current filter, we want to consider Cold rating as well, along with Warm rating, we can update our filter as shown below:
import { LightningElement } from 'lwc';

export default class RecordPickerDemo extends LightningElement {

    filter = {
        criteria: [
            {
                fieldPath: 'Rating',
                operator: 'eq',
                value: 'Warm'
            },
            {
                fieldPath: 'Rating',
                operator: 'eq',
                value: 'Cold'
            }
        ],
        filterLogic: '1 OR 2'
    };

}
As you can see above, I've added one more filter criteria that specify the Rating as Cold along with the existing filter for Rating as Warm. Also, I've specified the filterLogic as 1 OR 2, where 1 corresponds to the first filter and 2 corresponds to the second filter, so basically here we're saying that the account rating should either be Warm or Cold. The updated results in our lookup are shown below:

Note: By default, if no filterLogic is defined, all filter criterias are applied using the keyword AND.

Display Additional Field in our Record Picker (Lookup) Search Results

Now, it's time to display an additional field value in our record picker search result. We can display only one field from the same/related object as the additional field. For example: if we want to display the rating as well - in the search results, we can do that as follows:
import { LightningElement } from 'lwc';

export default class RecordPickerDemo extends LightningElement {

    filter = {
        criteria: [
            {
                fieldPath: 'Rating',
                operator: 'eq',
                value: 'Warm'
            },
            {
                fieldPath: 'Rating',
                operator: 'eq',
                value: 'Cold'
            }
        ],
        filterLogic: '1 OR 2'
    };

    displayInfo = {
        additionalFields: ['Rating']
    }

}
If you notice above, we defined one more object named displayInfo. It has a property called additionalFields which is an array with single string value i.e. the API name of our additional field to query which is Rating in our case. I can use this displayInfo object and pass it to our record picker component in the html as shown below:
<template>
    <lightning-card hide-header label="Account Record Picker Card">
        <p class="slds-var-p-horizontal_small">
            <lightning-record-picker
                label="Select Account"
                placeholder="Type Something..."
                object-api-name="Account"
                filter={filter}
                display-info={displayInfo}
            ></lightning-record-picker>
        </p>
    </lightning-card>
</template>
If you noticed above, I added another property to our lightning-record-picker named display-info and it's referring to our displayInfo object which we created in our js. Now, the search results output is also displaying the rating as shown below:


As you can see, we're only getting accounts with rating Warm or Cold.

Can we query using a different field?

By default, records are queried using the name field. However, we can use a different primary field to query records as well. We can also specify an additional field to query records. Let's say we want to query records using Rating field. The updated code for the js file is provided below:

import { LightningElement } from 'lwc';

export default class RecordPickerDemo extends LightningElement {

    filter = {
        criteria: [
            {
                fieldPath: 'Rating',
                operator: 'eq',
                value: 'Warm'
            },
            {
                fieldPath: 'Rating',
                operator: 'eq',
                value: 'Cold'
            }
        ],
        filterLogic: '1 OR 2'
    };

    displayInfo = {
        additionalFields: ['Rating']
    }

    matchingInfo = {
        primaryField: { fieldPath: 'Rating' }
    }
}

If you notice above, I've defined a new object named matchingInfo. In this object, we can define primaryField as well as additionalFields that we want to use to query records. The primaryField is basically an object with single property named fieldPath which should have the API name of the field you want to use. For our example, the API name is Rating for the Rating field of account. Also, the updated html is shown below:

<template>
    <lightning-card hide-header label="Account Record Picker Card">
        <p class="slds-var-p-horizontal_small">
            <lightning-record-picker
                label="Select Account"
                placeholder="Type Something..."
                object-api-name="Account"
                filter={filter}
                display-info={displayInfo}
                matching-info={matchingInfo}
            ></lightning-record-picker>
        </p>
    </lightning-card>
</template>

As you can see above, the matchingInfo property from our js is assigned to matching-info property of our lightning-record-picker.

Now, the records will be queried on the basis of Rating and not Name as shown below:


We can update our code to define an additional field to be used to query records as well. Let's see the updated code:
import { LightningElement } from 'lwc';

export default class RecordPickerDemo extends LightningElement {

    filter = {
        criteria: [
            {
                fieldPath: 'Rating',
                operator: 'eq',
                value: 'Warm'
            },
            {
                fieldPath: 'Rating',
                operator: 'eq',
                value: 'Cold'
            }
        ],
        filterLogic: '1 OR 2'
    };

    displayInfo = {
        additionalFields: ['Rating']
    }

    matchingInfo = {
        primaryField: { fieldPath: 'Rating' },
        additionalFields: [ { fieldPath: 'Phone' } ]
    }
}
As you can see above, we defined another property named additionalFields which is an array where we can define additional fields. We can define only one additional field here. For our use case, I used the Phone field as an additional field. Now, I can also query records using Phone field as shown below:

Making the lightning-record-picker required

We can make our lightning-record-picker required as well using the required attribute. The updated HTML code is provided below:
<template>
    <lightning-card hide-header label="Account Record Picker Card">
        <p class="slds-var-p-horizontal_small">
            <lightning-record-picker
                label="Select Account"
                placeholder="Type Something..."
                object-api-name="Account"
                filter={filter}
                display-info={displayInfo}
                matching-info={matchingInfo}
                required
            ></lightning-record-picker>
        </p>
    </lightning-card>
</template>
As you can see above, I've added the required attribute to my lightning-record-picker tag. This is a boolean attribute so we don't need to specify any value. Just adding required means, it's true. We don't need to add it if we don't want to make our field as required. Now, if we don't select a record, by clicking on the record picker, we'll get the error message as shown below:
As you can see, there is a red asterisk (*) with Select Account label as well which specifies that the field is required.

Setting a default record using record id as the component is loaded

One common use case we can encounter is to setup a default record for our lightning-record-picker as it's loaded initially. We can do that using the value attribute. Let's do some changes in our js first:
import { LightningElement } from 'lwc';

export default class RecordPickerDemo extends LightningElement {

    filter = {
        criteria: [
            {
                fieldPath: 'Rating',
                operator: 'eq',
                value: 'Warm'
            },
            {
                fieldPath: 'Rating',
                operator: 'eq',
                value: 'Cold'
            }
        ],
        filterLogic: '1 OR 2'
    };

    displayInfo = {
        additionalFields: ['Rating']
    }

    matchingInfo = {
        primaryField: { fieldPath: 'Rating' },
        additionalFields: [ { fieldPath: 'Phone' } ]
    }

    recordId = '001H3000002jHRYIA2';
}
As you can see above, I've defined a new property in my js class named recordId. I have hardcoded it's value to the id of an account from my salesforce org. Now, I can update my HTML as well so that this account record is pre-selected in the lookup:
<template>
    <lightning-card hide-header label="Account Record Picker Card">
        <p class="slds-var-p-horizontal_small">
            <lightning-record-picker
                label="Select Account"
                placeholder="Type Something..."
                object-api-name="Account"
                filter={filter}
                display-info={displayInfo}
                matching-info={matchingInfo}
                required
                value={recordId}
            ></lightning-record-picker>
        </p>
    </lightning-card>
</template>
If you notice above, the value attribute of my record picker is assigned the recordId property which I defined in my js file. Now, as the component is loaded initially, the account record with this record id is pre-selected as shown below:

That's all for this tutorial, I hope you liked it. There are also some predefined events linked to lightning-record-picker which you can check in the official documentation here. Let me know if you need a tutorial for the same and I can create one. I will look forward to your feedback in the comments down below.


Happy Trailblazing!!

No comments:

Post a Comment