html code

Managing Picklists in Apex and Lightning Web Components

Picklists serve as a valuable tool for tailoring Salesforce objects, offering a reusable and administrator-friendly solution complete with built-in validation. Nevertheless, programmatically accessing picklist values can be challenging, and it’s crucial to grasp the diverse methods and potential challenges. This article will explore various approaches for retrieving picklist values in both Apex and Lightning Web Components.

Picklists offer an excellent means of tailoring Salesforce objects, delivering a reusable and user-friendly solution complete with inherent validation. Yet, programmatically retrieving picklist values isn’t a straightforward task, and it’s essential to grasp the array of techniques and potential challenges involved. In this article, we’ll delve into diverse methods for programmatically accessing picklist values in Apex and Lightning Web Components. We’ll also explore their limitations and provide best practices for selecting the most suitable approach based on your specific use case.

Leveraging Picklists in Apex

A prevalent approach for retrieving picklist values from a trigger or a server controller is employing dynamic Apex. Dynamic Apex extends beyond dynamic SOQL; it allows you to programmatically examine objects and fields using methods available in the Schema namespace. This technique empowers you to address questions such as: What fields belong to a specific object? What data type does a particular field possess? And what are the potential values associated with a picklist field?

The provided code example demonstrates how you can obtain picklist values for the “Industry” field within the “Account” object. This is achieved by utilizing the getDescribe() and getPicklistValues() methods, resulting in a list of Schema.PicklistEntry objects.

// Describe the Account.Industry field
Schema.DescribeFieldResult fieldDescription = Account.Industry.getDescribe();
// Get picklist values from field description
List entries = fieldDescription.getPicklistValues();

// Do something with entries
for (Schema.PicklistEntry entry : entries) {
/*
entry.getValue()
entry.getLabel()
entry.isActive()
entry.isDefaultValue()
*/
}

Although this method is effective and straightforward, it has three notable limitations:

  1. It depends on static, predefined object and field names.
  2. It retrieves values, even including inactive picklist entries.
  3. It doesn’t handle values specific to particular record types.

To overcome these limitations, you can readily tackle the first two issues by creating a versatile helper method. This method can operate with any field and exclusively retrieve active picklist entries.

// Retrieves active picklist values for a given object and field
// Example: getPicklistValues(Account.Industry)
public static List<Schema.PicklistEntry> getPicklistValues(
        Schema.sObjectField field) {

    // Get all picklist values
    List<Schema.PicklistEntry> entries = field.getDescribe().getPickListValues();

    // Only return active picklist values
    List<Schema.PicklistEntry> activeEntries = new List<Schema.PicklistEntry>();
    for (Schema.PicklistEntry entry : entries) {
        if (entry.isActive()) {
            activeEntries.add(entry);
        }
    }
    return activeEntries;
}

The provided code snippet is a basic implementation without any caching, and you can observe that it begins to become a bit more extensive.

Another crucial aspect, often overlooked when dealing with picklist values, is the ability for administrators to constrain picklist values for a particular record type. The dynamic Apex approach we discussed earlier doesn’t accommodate this situation. If you require access to picklist values tailored to specific record types, you’ll have to make a callout to the UI API endpoint:

/ui-api/object-info/{objectApiName}/picklist-values/{recordTypeId}/{fieldApiName}

For the sake of brevity, we won’t show the full Apex code in this post, but you can check out an implementation in the PicklistUtils repository. This project provides a reusable PicklistUtils utility class with full code coverage and caching. PicklistUtils helps you handle all picklist use cases with simple calls:

// 1. Retrieve active picklist values for an object with no record type
// ...with object and field references
List values = PicklistUtils.getPicklistValues(
Account.sObjectType,
Account.Industry
);
// ...or with object and field specified as strings
List values = PicklistUtils.getPicklistValues(
'Account',
'Industry'
);

// 2. Retrieve active picklist values for a specific record type
PicklistUtils.PicklistEntries values = PicklistUtils.getPicklistValues(
'CustomerRequest__c', // Object name
'0124H000000cz6R', // Record type id
'Priority__c' // Field name
);

Leveraging Picklists in Lightning Web Components

When developing a Lightning Web Component that relies on picklist values, one approach involves calling a custom Apex controller to fetch those values, as described in the preceding methods. However, the good news is that there’s a more straightforward solution. You can bypass Apex entirely by making a direct call to the UI API using the “getPicklistValues” wire adapter from the “lightning/uiObjectInfoApi” module.

The “getPicklistValues” adapter fetches all picklist values for a specified record type and field name. Using this adapter is advantageous for performance, as it leverages the Lightning Data Service cache. Furthermore, it reduces the amount of Apex code you need to create and maintain, eliminating the need for a custom Apex controller.

Here’s an example of how to retrieve all picklist values for the “Industry” field in the “Account” object:

import { LightningElement, wire } from 'lwc';
import { getPicklistValues } from 'lightning/uiObjectInfoApi';
import INDUSTRY_FIELD from '@salesforce/schema/Account.Industry';

export default class Example extends LightningElement {
    @wire(getPicklistValues, {
        recordTypeId: '012000000000000AAA', // Default record type Id
        fieldApiName: INDUSTRY_FIELD
    })
    getIndustryPicklistValues({ error, data }) {
        if (data) {
            /*
            Do something with data.defaultValue and data.values[]
            Values are represented as objects like this:
            {
                attributes: null,
                label: "Agriculture",
                validFor: [],
                value: "Agriculture"
            }
            */
        } else if (error) {
            // Handle error
        }
    }
}

For a comprehensive demonstration of how to employ “getPicklistValues” alongside other UI API adapters, please refer to the blog post titled “Retrieving Picklist Values Without Apex.”

Final Thoughts

That wraps up our exploration of the various methods for retrieving picklist values in both Apex and Lightning Web Components. To recap the best practices we’ve discussed in this article:

  1. Employ dynamic Apex for records without a specific record type.
  2. Make UI API callouts in Apex when working with record types.
  3. Utilize the UI API’s “getPicklistValues” wire adapter for Lightning Web Components.
  4. Consider utilizing an Apex utility class, such as PicklistUtils, to prevent code redundancy.