Working with Picklists in Apex and Lightning Web Components | Salesforce Developers Blog

Picklists are a great way to customize Salesforce objects, providing a reusable and admin-friendly solution with built-in validation. However, accessing picklist values programmatically is not straightforward, and it’s important to understand the various techniques and pitfalls involved. In this post, we’ll discuss different methods for accessing picklist values in Apex and Lightning Web Components. We’ll cover their limitations, and we’ll leave you with best practices for selecting the right approach (depending on your use case).

Using picklists in Apex

A common practice for accessing picklist values from a trigger or a server controller is to use dynamic Apex. Dynamic Apex isn’t limited to dynamic SOQL, in fact it lets you analyze objects and fields programmatically with methods from the Schema namespace. With this technique, you can answer questions like: What are the fields of an object? What is the type of a particular field? Or, what are the possible values of a picklist field?

The following code sample shows how you can retrieve picklist values for the “Industry” field of the “Account” object as a list of Schema.PicklistEntry using getDescribe() and getPicklistValues():

// 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()
*/
}

While this approach is functional and simple, it has three important limitations:

  1. It relies on hard-coded object and field names.
  2. It returns values that include inactive picklist values.
  3. It doesn’t handle values for specific record types.

You can easily address the first two issues by writing a generic helper method that works with any field and that only returns 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 above snippet is a naive implementation with no caching, but you can see that things start to get slightly more verbose.

Another important consideration (that’s often overlooked) when accessing picklists values is the fact that admins can restrict picklist values for a given record type. The dynamic Apex approach that we just covered does not support this scenario. If you need to work with picklist values for specific record types, you’ll need to do a callout to this 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
);

Using picklists in Lightning Web Components

If you are building a Lightning Web Component that relies on picklist values, you could call a custom Apex controller to retrieve those values with the methods that we just described. But the good news is that there’s a simpler solution. You can avoid Apex altogether by calling directly the UI API with the getPicklistValues wire adapter from the lightning/uiObjectInfoApi module.

The getPicklistValues adapter retrieves all picklist values for a given record type and field name. Using the adapter is interesting for performance reasons because it benefits from the Lightning Data Service cache. Additionally, this also reduces the amount of Apex code you have to maintain and test (no need for a custom Apex controller).

Here’s an example of how you can retrieve all picklist values for the Industry field of 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 complete example of how to use getPicklistValues in combination with other UI API adapters, see the Retrieving Picklist Values Without Using Apex blog post.

Closing words

This concludes our tour of the different techniques for accessing picklist values in Apex and Lightning Web Components. Here’s a recap of the best practices we covered in this post:

  • Use dynamic Apex when working with records with no record type.
  • Use UI API callouts when working with record types in Apex.
  • Use the UI API getPicklistValues wire adapter when working with Lightning Web Components.
  • Use an Apex utility class like PicklistUtils to avoid code duplication.

About the author

Philippe Ozil is a Principal Developer Advocate at Salesforce, where he focuses on the Salesforce Platform. He writes technical content and speaks frequently at conferences. He is a full stack developer and enjoys working on DevOps, robotics, and VR projects. Follow him on Twitter @PhilippeOzil or check his GitHub projects @pozil.

Stay up to date with the latest news from the Salesforce Developers Blog

Subscribe