How to get Dependent Picklist Values in Apex?

Introduction

According to Salesforce Help:
“A dependent picklist is a custom or multi-select picklist for which the valid values depend on the value of another field, called the controlling field. Controlling fields can be any picklist (with at least one and fewer than 300 values) or checkbox field on the same record.

For example, you can define a Reason custom picklist on opportunities and make its valid values depend on the value of the Stage picklist as follows:

  • If Stage is Closed Won, the valid values for Reason are Superior features or Lower price.
  • If Stage is Closed Lost, the valid values for Reason are Inferior features, Higher Price or Company viability.

Problem

Using Schema class, you can get all picklist values for a field, including inactive ones. Unfortunately Salesforce doesn’t provide any method to get values that depend on a particular controlling field value. There is an idea on Salesforce Community, but still the method is not implemented.

Solution

Using Schema.PicklistEntry and Base64, you can implement the method which solves a problem:

public static Map<String, List<String>> getDependentPicklistValues(Schema.sObjectField dependToken) {
    Schema.DescribeFieldResult depend = dependToken.getDescribe();
    Schema.sObjectField controlToken = depend.getController();
    if (controlToken == null) {
        return new Map<String, List<String>>();
    }

    Schema.DescribeFieldResult control = controlToken.getDescribe();
    List<Schema.PicklistEntry> controlEntries;
    if(control.getType() != Schema.DisplayType.Boolean) {
        controlEntries = control.getPicklistValues();
    }

    String base64map = 'ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/';
    Map<String,List<String>> dependentPicklistValues = new Map<String,List<String>>();
    for (Schema.PicklistEntry entry : depend.getPicklistValues()) {
        if (entry.isActive() && String.isNotEmpty(String.valueOf(((Map<String,Object>) JSON.deserializeUntyped(JSON.serialize(entry))).get('validFor')))) {
            List<String> base64chars =
                    String.valueOf(((Map<String,Object>) JSON.deserializeUntyped(JSON.serialize(entry))).get('validFor')).split('');
            for (Integer index = 0; index < (controlEntries != null ? controlEntries.size() : 2); index++) {
                Object controlValue =
                        (controlEntries == null
                                ?   (Object) (index == 1)
                                :   (Object) (controlEntries[index].isActive() ? controlEntries[index].getLabel() : null)
                        );
                Integer bitIndex = index / 6;
                if (bitIndex > base64chars.size() - 1) {
                    break;
                }
                Integer bitShift = 5 - Math.mod(index, 6);
                if  (controlValue == null || (base64map.indexOf( base64chars[ bitIndex ] ) & (1 << bitShift)) == 0)
                    continue;
                if (!dependentPicklistValues.containsKey((String) controlValue)) {
                    dependentPicklistValues.put((String) controlValue, new List<String>());
                }
                dependentPicklistValues.get((String) controlValue).add(entry.getLabel());
            }
        }
    }
    return dependentPicklistValues;
}

How to use?

Example of field dependency between the Stage (Controlling field) and the Close Reasons (Dependent field):

Controlling-Dependent field configuration

Invoking a method:

Map<String,List<String>> dependentPicklistValuesMap = getDependentPicklistValues(Opportunity.Close_Reasons__c);

Result:

Resources

Was it helpful? Check out our other great articles here.

4.3 4 votes
Article Rating
Subscribe
Notify of
guest
13 Comments
Newest
Oldest Most Voted
Inline Feedbacks
View all comments
Shashank
Shashank
3 months ago

how to use that in vf page

Kevin
Kevin
4 months ago

In my controlling picklist I have 10 values, and with this logic it only shows me two of ten values. Is there any reason why that might occur?

Krista
Krista
9 months ago

This works as expected with custom picklist values for both parent and dependent picklists. But I am getting the List Index out of bounds issue with Globally available picklist values, such as Days of the Week. Any workarounds besides creating a new “Custom” version of the same picklist? Thank you!

Diego
Diego
1 year ago

Thank you Pawel, definitely implementing this in a utility class!!

Akshata Rane
Akshata Rane
1 year ago

I am facing List Index out of bounds : 4 exception while execution of line (base64map.indexOf( base64chars[ bitIndex ] ) & (1 << bitShift)) == 0
Can you please help

rohan
rohan
1 year ago

I am facing exception of out of index

Roman
Roman
1 year ago

Many thanks, Paweł! Works like expected!

Close Menu
13
0
Would love your thoughts, please comment.x
()
x