Various Methods For Associating Picklist Values in Lightning Web Components (LWC)

In this article, we will delve into different approaches for linking picklist values in LWC and implementing them within the application.

Within the specified LWC component, three distinct picklist fields—Type, Industry, and Rating—are employed. Let’s examine the methods used to bind picklist values for these fields.

1. Employing the UI Object Info API

The initial method for associating picklist values involves leveraging the UI Object Info API. This API enables the retrieval of metadata information related to an object, allowing us to obtain the list of picklist values for a specific field. Within the provided LWC component, the Metadata API is utilized to bind the picklist values for the Type field from the Account Object.

To implement the UI Object Info API, it is necessary to import the ‘getPicklistValues’ function from the ‘lightning/uiObjectInfoApi’ module. Subsequently, the ‘@wire’ decorator is employed to wire the function to our component. Within the wired property, data values are mapped to an array of options, which is then utilized to populate the lightning-combobox component.

Sample Code:

JS -
// Import getPicklistValues function from uiObjectInfoApi module
import { getPicklistValues } from 'lightning/uiObjectInfoApi';
// Import constant TYPE_FIELD from Account schema
import TYPE_FIELD from '@salesforce/schema/Account.Type';
// Wire getPicklistValues function from uiObjectInfoApi module to the component
    @wire(getPicklistValues, {
        recordTypeId: '012000000000000AAA', // Specify record type ID , if no record type is there specify default record type
        fieldApiName: TYPE_FIELD // Specify field API name
    })
HTML -
<lightning-combobox label="Type" value={accountType} options={typeOptions}
                onchange={handleAccountTypeChange}>
            </lightning-combobox>


Advantages:

  1. Simplicity: The lightning/uiObjectInfoApi module offers a straightforward and declarative approach to fetch picklist values through a standardized API, enhancing developer ease in customizing and maintaining applications.
  2. Up-to-Date: Utilizing the standard API ensures the constant availability of the latest picklist values, eliminating the need for manual updates to an Apex class.
  3. Consistency: The standard API guarantees uniformity in picklist values throughout the organization, adhering to any custom business logic or validation rules configured for the picklist field.
  4. Support for Record Types: When dealing with objects featuring record types, picklist values can be retrieved based on the record type assignment within the organization.
  5. Compatibility: This approach is supported for all custom objects and the majority of standard objects.

Disadvantages:

  1. Performance: The use of the lightning/uiObjectInfoApi module might impact performance due to additional client-server round trips, especially in applications with increased complexity and numerous picklist fields.
  2. API Limits: Depending on the volume of API calls and the number of picklist fields requiring retrieval, there is a risk of encountering API limits or incurring additional costs when relying on third-party API providers.
  3. Limited Flexibility: While the lightning/uiObjectInfoApi module provides a straightforward means of obtaining picklist values, it may lack the same level of flexibility or control as retrieving values from an Apex class. For instance, dynamic changes to available picklist values based on specific conditions or the addition of custom logic for selected values might be restricted.
  4. Not Supported for External Objects: This approach is not applicable for external objects, and certain standard objects may also lack support. It is crucial to refer to Salesforce documentation to confirm support before implementation. Check Salesforce Objects Supported by lightning/ui*Api Modules in the Salesforce Lightning Component Library and the User Interface API Developer Guide.

2. Employing manually specified values in JavaScript for PickList Options

The second way to bind picklist values is by using hardcoded values. In the given LWC component, we have used this approach to bind the picklist values for the Industry field from Account Object.

To use hardcoded values, we simply define an array of options in our component and use it to populate the lightning-combobox component.

JS - 
// Define an array of industry options
    industryOptions = [
        { label: 'Agriculture', value: 'Agriculture' },
        { label: 'Apparel', value: 'Apparel' },
        { label: 'Banking', value: 'Banking' },
        { label: 'Biotechnology', value: 'Biotechnology' },
        { label: 'Chemicals', value: 'Chemicals' }
    ];
HTML -
<lightning-combobox label="Industry" value={accountIndustry} options={industryOptions}
                onchange={handleAccountIndustryChange}></lightning-combobox>

Advantages:

  1. Dynamic options: Defining picklist options in JavaScript allows for the creation of dynamic options based on data obtained from the server or user input. This flexibility enables updates to options without necessitating server-side modifications.
  2. Client-side rendering: When rendering the picklist on the client side using JavaScript, specifying options in JavaScript facilitates easy manipulation and updating of picklist options in response to user interactions.
  3. Improved performance: By defining options in JavaScript, the need for multiple server requests to retrieve picklist options is eliminated, leading to enhanced performance and reduced server load.

Disadvantages:

  1. Lack of server-side validation: The absence of server-side validation may result in data inconsistencies if picklist options solely rely on JavaScript and do not align with the data stored on the server.
  2. Potential security risks: Inadequate sanitization of picklist options defined in JavaScript may pose potential security vulnerabilities, such as susceptibility to cross-site scripting (XSS) attacks.

3. Leveraging an Apex Controller

The third way to bind picklist values is by using an Apex controller. In the given LWC component, we have used this approach to bind the picklist values for the Rating field from Account Object.

To use an Apex controller, we first need to define the Apex method that returns the picklist values. We then import this method into our LWC component using the ‘@salesforce/apex’ module. We then use the ‘@wire’ decorator to wire the method to our component. In the wired property, we map the data to an array of options, which we use to populate the lightning-combobox component.

JS -
// Import getRatingPicklistValues function from Apex controller
import getRatingPicklistValues from '@salesforce/apex/AccountController.getPicklistValues';
// Wire getRatingPicklistValues function from Apex controller to the component
    @wire(getRatingPicklistValues, {})
    // Define a wired property for rating picklist values
    wiredRatingPicklistValues({ error, data }) {
        // If data is returned from the wire function
        if (data) {
            // Map the data to an array of options
            this.ratingOptions = data.map(option => {
                return {
                    label: option.label,
                    value: option.value
                };
            });
        }
        // If there is an error
        else if (error) {
            // Log the error to the console
            console.error(error);
        }
    }
HTML -
<lightning-combobox label="Rating" value={accountRating} options={ratingOptions}
                onchange={handleAccountRatingChange}></lightning-combobox>
Apex - 
@AuraEnabled(cacheable=true)
    public static List<Map<String, String>> getPicklistValues() {
        List<Schema.PicklistEntry> entries = Account.Rating.getDescribe().getPicklistValues();
        List<Map<String, String>> values = new List<Map<String, String>>();
        for (Schema.PicklistEntry entry : entries) {
            Map<String, String> valueMap = new Map<String, String>();
            valueMap.put('label', entry.getLabel());
            valueMap.put('value', entry.getValue());
            values.add(valueMap);
        }
        return values;
    }

Advantages:

  1. More Control: Retrieving picklist values from an Apex class provides greater control over how these values are presented or utilized within the application. For instance, dynamic alterations to available picklist values based on specific conditions or the inclusion of custom logic for selected values can be implemented.
  2. Better Performance: Utilizing a cached, server-side call to fetch picklist values enhances application performance by minimizing the number of client-server round trips required for retrieval.
  3. Flexibility: Exposing a picklist values method through an Apex class allows its use across various components, pages, or even multiple applications. This facilitates code reuse and maintenance of a consistent user experience throughout the organization.

Disadvantages:

  1. Maintenance: If picklist values undergo frequent changes, keeping an Apex class up to date may be more challenging compared to using a standard picklist field in the UI. Updates to the Apex class would be necessary whenever picklist values change.
  2. No Support for Record Types: Presently, there is no support for obtaining picklist values based on record type. Custom logic is required to customize options in such cases (refer to Getting Picklist values based on Record Type | IdeaExchange).

The following is a comprehensive sample code demonstrating the three mentioned approaches:

  • Binding the Type field using UI Object Info API
  • Binding the Industry field using hardcoded values in JS for PickList Options
  • Binding the Rating field using an Apex Controller
<template>
    <lightning-card title="Account Form">
        <div class="slds-m-around_medium">
            <lightning-combobox label="Type" value={accountType} options={typeOptions}
                onchange={handleAccountTypeChange}>
            </lightning-combobox>
            <lightning-combobox label="Industry" value={accountIndustry} options={industryOptions}
                onchange={handleAccountIndustryChange}></lightning-combobox>
            <lightning-combobox label="Rating" value={accountRating} options={ratingOptions}
                onchange={handleAccountRatingChange}></lightning-combobox><br />
            Selected Type - {accountType} <br />
            Selected Industry - {accountIndustry} <br />
            Selected Rating - {accountRating}
        </div>
    </lightning-card>
</template>

JS

// Import LightningElement and wire decorator from LWC module
import { LightningElement, wire } from 'lwc';
// Import getPicklistValues function from uiObjectInfoApi module
import { getPicklistValues } from 'lightning/uiObjectInfoApi';
// Import getRatingPicklistValues function from Apex controller
import getRatingPicklistValues from '@salesforce/apex/AccountController.getPicklistValues';
// Import constant TYPE_FIELD from Account schema
import TYPE_FIELD from '@salesforce/schema/Account.Type';
export default class AccountForm extends LightningElement {
    // Initialize properties for the component
    accountType = ''; // Set default value for accountType
    accountIndustry = ''; // Set default value for accountIndustry
    accountRating = ''; // Set default value for accountRating
    typeOptions = []; // Initialize typeOptions as an empty array
    ratingOptions = []; // Initialize ratingOptions as an empty array
    // Define an array of industry options
    industryOptions = [
        { label: 'Agriculture', value: 'Agriculture' },
        { label: 'Apparel', value: 'Apparel' },
        { label: 'Banking', value: 'Banking' },
        { label: 'Biotechnology', value: 'Biotechnology' },
        { label: 'Chemicals', value: 'Chemicals' }
    ];
    // Wire getPicklistValues function from uiObjectInfoApi module to the component
    @wire(getPicklistValues, {        
        recordTypeId: '012000000000000AAA', // Specify record type ID , if no record type is there specify default record type
        fieldApiName: TYPE_FIELD // Specify field API name
    })
    // Define a wired property for type picklist values
    wiredTypePicklistValues({ error, data }) {
        // If data is returned from the wire function
        if (data) {
            // Map the data values to an array of options
            this.typeOptions = data.values.map(option => {
                return {
                    label: option.label,
                    value: option.value
                };
            });
        }
        // If there is an error
        else if (error) {
            // Log the error to the console
            console.error(error);
        }
    }
    // Wire getRatingPicklistValues function from Apex controller to the component
    @wire(getRatingPicklistValues, {})
    // Define a wired property for rating picklist values
    wiredRatingPicklistValues({ error, data }) {
        // If data is returned from the wire function
        if (data) {
            // Map the data to an array of options
            this.ratingOptions = data.map(option => {
                return {
                    label: option.label,
                    value: option.value
                };
            });
        }
        // If there is an error
        else if (error) {
            // Log the error to the console
            console.error(error);
        }
    }
    // Define a method to handle changes to the account type
    handleAccountTypeChange(event) {
        // Set the account type to the selected value
        this.accountType = event.target.value;
    }
    // Define a method to handle changes to the account industry
    handleAccountIndustryChange(event) {
        // Set the account industry to the selected value
        this.accountIndustry = event.target.value;
    }
    // Define a method to handle changes to the account rating
    handleAccountRatingChange(event) {
        // Set the account rating to the selected value
        this.accountRating = event.target.value;
    }
}

Apex

public with sharing class AccountController {
    /**
    * Retrieves the picklist values for the Rating field of the Account object.
    * @return A list of maps, where each map contains the label and value of a picklist value.
    */
    @AuraEnabled(cacheable=true)
    public static List<Map<String, String>> getPicklistValues() {
        // Retrieve the picklist values for the Rating field of the Account object.
        List<Schema.PicklistEntry> entries = Account.Rating.getDescribe().getPicklistValues();
        // Create a list to hold the label and value of each picklist value.
        List<Map<String, String>> values = new List<Map<String, String>>();
        // Loop through the picklist values and add the label and value to the list.
        for (Schema.PicklistEntry entry : entries) {
            // Create a map to hold the label and value of the picklist value.
            Map<String, String> valueMap = new Map<String, String>();
            // Add the label and value to the map.
            valueMap.put('label', entry.getLabel());
            valueMap.put('value', entry.getValue());
            // Add the map to the list.
            values.add(valueMap);
        }
        // Return the list of maps.
        return values;
    }