• Stars
    star
    582
  • Rank 76,801 (Top 2 %)
  • Language
    JavaScript
  • License
    Apache License 2.0
  • Created almost 6 years ago
  • Updated 3 months ago

Reviews

There are no reviews yet. Be the first to send feedback to the community and the maintainers!

Repository Details

Salesforce Lookup Component built with Lightning Web Components.

Salesforce Lookup Component

Github Workflow codecov a11y friendly

Lookup animation

Lookup with dropdown open

  1. About
  2. Installation
  3. Documentation
    1. Getting started
    2. Handling selection changes (optional)
    3. Providing default search results (optional)
    4. Saving form state when creating new records (optional)
    5. Passing custom data to JavaScript and Apex (optional)
  4. Reference
  5. Special use cases
    1. Working with picklists values

About

This is a generic & customizable lookup component built using Salesforce Lightning Web Components and SLDS style.
It does not rely on third party libraries and you have full control over its datasource.

Features

The lookup component provides the following features:

  • customizable data source that can return mixed sObject types
  • single or multiple selection mode
  • client-side caching & request throttling
  • great test coverage
  • full accessibility (a11y) compliance
  • keyboard navigation
  • search term highlighting
  • ability to create new records

Multiple or single entry lookup

Installation

The default installation installs the lookup component and a sample application available under this URL (replace the domain):
https://YOUR_DOMAIN.lightning.force.com/c/SampleLookupApp.app

If you wish to install the project without the sample application, edit sfdx-project.json and remove the src-sample path.

Install the sample app by running this script:

MacOS or Linux

./install-dev.sh

Windows

install-dev.bat

Documentation

Getting Started

Follow these steps to use the lookup component:

  1. Write the search endpoint

    Implement an Apex @AuraEnabled(cacheable=true scope='global') method (SampleLookupController.search in our samples) that returns the search results as a List<LookupSearchResult>. The method name can be different, but it needs to match this signature:

    @AuraEnabled(cacheable=true scope='global')
    public static List<LookupSearchResult> search(String searchTerm, List<String> selectedIds) {}
  2. Import a reference to the search endpoint

    Import a reference to the search Apex method in the lookup parent component's JS:

    import apexSearch from '@salesforce/apex/SampleLookupController.search';
  3. Handle the search event and pass search results to the lookup

    The lookup component exposes a search event that is fired when a search needs to be performed on the server-side. The parent component that contains the lookup must handle the search event:

    <c-lookup onsearch={handleSearch} label="Search" placeholder="Search Salesforce">
    </c-lookup>

    The search event handler calls the Apex search method and passes the results back to the lookup using the setSearchResults(results) function:

    handleSearch(event) {
        const lookupElement = event.target;
        apexSearch(event.detail)
            .then(results => {
                lookupElement.setSearchResults(results);
            })
            .catch(error => {
                // TODO: handle error
            });
    }

Handling selection changes (optional)

The lookup component exposes a selectionchange event that is fired when the selection of the lookup changes. The parent component that contains the lookup can handle the selectionchange event:

<c-lookup onsearch={handleSearch} onselectionchange={handleSelectionChange}
    label="Search" placeholder="Search Salesforce">
</c-lookup>

The selectionchange event handler can then get the current selection from the event detail or by calling the getSelection() function:

handleSelectionChange(event) {
    // Get the selected ids from the event (same interface as lightning-input-field)
    const selectedIds = event.detail;
    // Or, get the selection objects with ids, labels, icons...
    const selection = event.target.getSelection();
    // TODO: do something with the lookup selection
}

getSelection() always return a list of selected items. That list contains a maximum of one element if the lookup is a single-entry lookup.

Providing default search results (optional)

The lookup can return default search results with the setDefaultResults(results) function. This is typically used to return a list of recently viewed records (see sample app).

Here's how you can retrieve recent records and set them as default search results:

  1. Implement an Apex endpoint that returns the recent records:

    @AuraEnabled(cacheable=true scope='global')
    public static List<LookupSearchResult> getRecentlyViewed()

    See the full code from the sample app

  2. In your parent component, create a property that holds the default results:

    recentlyViewed = [];
  3. Write a utility function that sets your default search results:

    initLookupDefaultResults() {
        // Make sure that the lookup is present and if so, set its default results
        const lookup = this.template.querySelector('c-lookup');
        if (lookup) {
            lookup.setDefaultResults(this.recentlyViewed);
        }
    }
  4. Retrieve the recent records by calling your endpoint:

    @wire(getRecentlyViewed)
    getRecentlyViewed({ data }) {
        if (data) {
            this.recentlyViewed = data;
            this.initLookupDefaultResults();
        }
    }
  5. Initialize the lookup default results when the parent component loads:

    connectedCallback() {
        this.initLookupDefaultResults();
    }

Note: initLookupDefaultResults() is called in two places because the wire could load before the lookup is rendered.

Saving form state when creating new records (optional)

The lookup component allows the user to create new record thanks to the optional newRecordOptions attribute. When users create a new record, they navigate away to the record edit form and they lose their current form input (lookup selection and more).

To prevent that from happening, you may provide an optional callback that lets you store the lookup state before navigating away. To do that, initialize the lookup new record options with a preNavigateCallback when the parent component loads:

connectedCallback() {
    /**
     * This callback is called before navigating to the new record form
     * @param selectedNewRecordOption the new record option that was selected
     * @return Promise - once resolved, the user is taken to the new record form
     */
    const preNavigateCallback = (selectedNewRecordOption) => {
        return new Promise((resolve) => {
            // TODO: add some preprocessing (i.e.: save the current form state)

            // Always resolve the promise otherwise the new record form won't show up
            resolve();
        });
    };

    // Assign new record options with the pre-navigate callback to your lookup
    this.newRecordOptions = [
        { value: 'Account', label: 'New Account', preNavigateCallback },
        { value: 'Opportunity', label: 'New Opportunity', preNavigateCallback }
    ];
}

Tip: consider working with cookies to store information in a temporary state.

Passing custom data to JavaScript and Apex (optional)

Sometimes, you may want to pass extra data from the lookup component to Apex. To do so, use dataset attributes:

  1. In the parent component that uses the lookup, add a dataset attribute (data-custom in this example):

    <c-lookup
        selection={initialSelection}
        onsearch={handleLookupSearch}
        label="Search"
        is-multi-entry={isMultiEntry}
        data-custom="My custom value"
    >
  2. In the parent JS, use the dataset attribute that you just added:

    handleLookupSearch(event) {
        const lookupElement = event.target;
    
        alert(lookupElement.dataset.custom); // My custom value
    
        // Actual search code
    }

Reference

Attributes

Attribute Type Description Default
disabled Boolean Whether the lookup selection can be changed. false
errors [{ "id": String, "message": String }] List of errors that are displayed under the lookup. When passing a non-empty list, the component is blurred. []
isMultiEntry Boolean Whether the lookup is single (default) or multi entry. false
label String Optional (but recommended) lookup label. Label is hidden if attribute is omitted but this breaks accessibility. If you don't want to display it, we recommend to provide a label but hide it with variant="label-hidden". ''
minSearchTermLength Number Minimum number of characters required to perform a search. 2
newRecordOptions [{ "value": String, "label": String, "defaults": String, "preNavigateCallback": Function }] List of options that lets the user create new records.
value is an sObject API name (i.e.: "Account")
label is the label displayed in the lookup (i.e.: "New Account").
defaults is an optional comma-separated list of default field values (i.e.: "Name=Foo,Type__c=Bar")
preNavigateCallback is an optional callback used for saving the form state before navigating to the new record form.
[]
placeholder String Lookup placeholder text. ''
required Boolean Whether the lookup is a required field. Note: Property can be set with <c-lookup required>. false
scrollAfterNItems Number A null or integer value used to force overflow scroll on the result listbox after N number of items.
Valid values are null, 5, 7, or 10.
Use null to disable overflow scrolling.
null
selection [LookupSearchResult] OR LookupSearchResult Lookup initial selection if any. Array for multi-entry lookup or an Object for single entry lookup. []
validity { "valid": Boolean } Read-only property used for datatable integration. Reports whether there are errors or not (see errors). false
value [LookupSearchResult] OR LookupSearchResult Read-only property used for datatable integration. Alias of selection. false
variant String Changes the appearance of the lookup. Accepted variants:
label-stacked - places the label above the lookup.
label-hidden - hides the label but make it available to assistive technology.
label-inline - aligns horizontally the label and lookup.
label-stacked

Functions

Function Description
focus() Places focus on the component an opens the search dropdown (unless this is a single selection lookup with a selection).
blur() Removes focus from the component and closes the search results list.
getSelection() Gets the current lookup selection as an array of LookupSearchResult.
setDefaultResults(results) Allows to set optional default items returned when search has no result (ex: recent items).
results is an array of LookupSearchResult.
setSearchResults(results) Passes a search result array back to the lookup so that they are displayed in the dropdown.
results is an array of LookupSearchResult.

Events

Event Description event.detail Type
search Event fired when a search needs to be performed on the server-side.
searchTerm is the sanitized (lowercase, trimmed...) search term that should be sent to the server.
rawSearchTerm is the unsanitized user input.
selectedIds is an array of selected record Ids.
{ searchTerm: String, rawSearchTerm: String, selectedIds: [ String ] }
selectionchange Event fired when the selection of the lookup changes. The event's detail property holds the list of selected ids.
You can also use target.getSelection() to retrieve the selected lookup objects.
[ String ]

Special use cases

Working with picklists values

The lookup component can also be used to select values from picklist fields.

This Apex sample example demonstrates how you can query for the values of Account.Industry:

@AuraEnabled(cacheable=true scope='global')
public static List<LookupSearchResult> search(String searchTerm, List<String> selectedIds) {
    // Prepare query parameters
    searchTerm = '%' + searchTerm + '%';
    // Execute search query
    List<PicklistValueInfo> entries = [
        SELECT Label, Value
        FROM PicklistValueInfo
        WHERE
            EntityParticle.EntityDefinition.QualifiedApiName = 'Account'
            AND EntityParticle.QualifiedApiName = 'Industry'
            AND isActive = TRUE
            AND Label LIKE :searchTerm
            AND Value NOT IN :selectedIds
        LIMIT 5
    ];
    // Prepare results
    List<LookupSearchResult> results = new List<LookupSearchResult>();
    for (PicklistValueInfo entry : entries) {
        results.add(new LookupSearchResult(entry.Value, null, null, entry.Label, null));
    }
    return results;
}

More Repositories

1

streaming-monitor

A Lightning app for monitoring streaming events: PushTopic, generic, platform events, CDC events and monitoring events.
JavaScript
121
star
2

sfdc-ui-lookup

Salesforce Lookup Component (Aura version, maintenance only, see LWC version for updates)
JavaScript
102
star
3

pub-sub-api-node-client

A node client for the Salesforce Pub/Sub API
JavaScript
70
star
4

salesforce-react-integration

Sample integration project between Salesforce and a React.js application
JavaScript
68
star
5

ui-api-playground

A sample Lightning Web Component (LWC) app that lets you explore the UI APIs and execute them.
JavaScript
64
star
6

auto-assign-issue

GitHub Action that auto-assigns issues or PRs to one or more users
JavaScript
55
star
7

apex-dependency-injection

Apex Dependency Injection Sample
Apex
38
star
8

sfdc-error-playground

Lightning & Apex Error Playground
JavaScript
31
star
9

sfdc-lightning-component-event-playground

Lightning Component Event Playground
JavaScript
30
star
10

sfdc-ui-modal

Salesforce Lightning Modal Component (Deprecated)
JavaScript
26
star
11

sf-docs-to-s3

Export Salesforce Documents to Amazon S3
Apex
23
star
12

spm-plugin

A Salesforce CLI plugin for interacting with the unofficial Salesforce Package Manager (SPM) registry.
TypeScript
22
star
13

picklist-utils

Apex utility class for working with Picklists with built-in cache
Apex
21
star
14

server-action-service

Generic and reusable Lightning service component that calls server-side actions
JavaScript
20
star
15

sfdc-ui-tree

Salesforce Lightning Tree Component (Deprecated)
JavaScript
20
star
16

csv-visualizer

A visualizer that parses CSV data and renders it in a table in Postman or in a browser.
JavaScript
19
star
17

bonita-angular-dashboard

Bonita Dashboard built on AngularJS integrated as a custom page (Deprecated)
JavaScript
18
star
18

legacy-api-scanner

Scan for Salesforce Legacy API calls
17
star
19

salesforce-unity-sdk

Salesforce SDK for Unity
C#
16
star
20

async-lwc-demo

Asynchronous Lightning Web Component Demo
JavaScript
16
star
21

dynamic-interactions-demo

Sample Lightning Web Component (LWC) app that lets you explore Dynamic Interactions.
JavaScript
15
star
22

codetour-watch

GitHub Action that flags file changes that may affect CodeTour content
JavaScript
15
star
23

sf-docs-from-s3

Middleware app that allows to download Amazon S3 documents from Salesforce
JavaScript
15
star
24

sandbox-user-init

Sandbox initialization class that creates admin users based on custom metadata from production
Apex
13
star
25

apex-sorting

Sample Code for Sorting in Apex
Apex
13
star
26

pub-sub-api-java-client

A sample Java gRPC client for the Salesforce Pub/Sub API
Java
12
star
27

picklist-service

Generic and reusable Lightning service component that retrieves picklist entries (Archived)
Apex
12
star
28

picklist-buttons

LWC, picklist, buttons
JavaScript
10
star
29

sfdc-ui-popover

Salesforce Lightning Popover Component (Deprecated)
CSS
10
star
30

sfdc-ui-modal-sample

Sample application for Lightning Modal component
JavaScript
8
star
31

lightning-singleton

Lightning component that acts a singleton
JavaScript
8
star
32

apex-security-update-summer21

Helper script for Salesforce Summer '21 Apex security update
Java
7
star
33

platform-event-service

Generic and reusable Lightning service component that publishes and subscribes to platform events (Partially Deprecated)
JavaScript
7
star
34

mongodb-jndi-datasource

A JNDI pooled datasource for MongoDB
Java
6
star
35

lws-fullcalendar-test

Testing FullCalendar lib with LWS
JavaScript
6
star
36

image-labeller

Image labeller for Salesforce Einstein Object Detection
JavaScript
5
star
37

bonita-angular-portal

A custom portal for Bonita BPM built with AngularJS and Bootstrap (Deprecated)
HTML
5
star
38

whac-a-console-app

A fun game of speed and skills that demonstrates how to navigate Console apps with LWC.
JavaScript
5
star
39

pardot-embedded-feedback

Gather instant feedback from prospects within Pardot Emails with Lightning Web Components.
JavaScript
4
star
40

pwm-controller

Node.js React app that controls servos via a PWM Hat mounted on a Raspberry Pi
JavaScript
4
star
41

devops-workshop

DevOps workshop with Lightning Web Runtime and GitHub Actions
JavaScript
3
star
42

spm-registry

This repository contains the SPM registry
JavaScript
3
star
43

postman-extractor

Postman Extractor (pmx) is a utility that extracts/compacts resources from Postman export files for easier versioning.
JavaScript
3
star
44

d3-word-cloud-lwc

A D3 Word Cloud Lightning Web Component
JavaScript
3
star
45

emp-api-test

JavaScript
2
star
46

gcal-cleaner

Google Calendar cleaner app
JavaScript
2
star
47

styling-lwc-oss

A sample LWC OSS application using a third party CSS Framework (Bulma)
HTML
2
star
48

lwc-svg-sample

Shell
1
star
49

salesforce-wef-vr

Salesforce Shelter VR Workshop
1
star
50

search-replace

JavaScript
1
star
51

bonita-doc-manager

Bonita Document Manager Custom Page implemented with AngularJS (Deprecated)
JavaScript
1
star
52

lwc-style-challenge

Base project for the LWC Style Challenge
HTML
1
star
53

lwc-picklist-path

A LWC path component that works with any picklist field
JavaScript
1
star
54

cometd-node-client

CometD client for Node.js that adds support for promises
JavaScript
1
star
55

event-lab-demo

TDX/DF LAB demo
Shell
1
star