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):

Invoking a method:
Map<String,List<String>> dependentPicklistValuesMap = getDependentPicklistValues(Opportunity.Close_Reasons__c);
Result:

Resources
- https://help.salesforce.com/articleView?id=fields_about_dependent_fields.htm&type=5
- https://glyntalkssalesforce.blogspot.com/2018/08/dependent-picklist-values-in-apex.html
Was it helpful? Check out our other great articles here.
how to use that in vf page
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?
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!
Thank you Pawel, definitely implementing this in a utility class!!
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
I am facing exception of out of index
Many thanks, Paweł! Works like expected!