Building a website or app experience with dependent picklists is a great way to ensure your users are able to enter accurate, consistent data. Recently, I was developing an application for a customer when I encountered a situation where I needed to fetch dependent picklist values for each controlling picklist field. And since Salesforce doesn’t currently offer a way to natively fetch this type of value set, I decided to go the API route.
To solve for this, I set out to create a simple way to fetch dependent picklist values for each controlling picklist field in Apex.
After reading through the API docs for DescribeSObjectResult, I learned that the picklist entry object has validFor property, which is not accessible through Apex. Instead, it can be accessed through an API. If you serialize the picklist entry to JSON, validFor property should become available. Then, you can deserialize the content into a custom type.
Solution
Create a class that represents a json version to expose validFor property:
Code snippet if you’d like to copy-paste:
/* Summary: Entity to represent a json version of a picklist entry
* So that the validFor property becomes exposed
*/
public class MyPickListInfo {
public String validFor;
}
The code below is documented at line level for readability purposes. Here are a few things to know before building the class:
- To prepare for an arbitrary string to SObjectTypeassociation: getGlobalDescribe() gives us a map of String to SObjectTypes.
- To prepare for an arbitrary field to SObjectFieldassociation: For an entity of type SObjectType, we have access to <MyEntity>.getDescribe().fields.getMap();
Code snippet if you’d like to copy-paste:
/*Summary : Code snippet to access picklist value set */
global static Map<String, List<String>> getGlobalPickList( ) {
//Define table name that has picklist value set fields
String objectName = ‘opportunity’;
//Define controlling picklist value field
String controllingField = ‘category__c’ ;
//Define dependent picklist value field
String dependentField = ‘subcategory__c’ ;
//Declare map variable to store list of dependent value for controlling field
Map<String, List<String>> controllingInfo = new Map<String, List<String>>( ) ;
//Get the type being dealt with
Schema.SObjectType objType = Schema.getGlobalDescribe( ).get(objectName) ;
Schema.DescribeSObjectResult describeResult = objType.getDescribe ( ) ;
//Get controlling field values
Schema.DescribeFieldResult controllingFieldInfo = describeResult.fields.getMap ( )
.get (controllingField)
.getDescribe ( ) ;
//Get dependent field values
Schema.DescribeFieldResult dependentFieldInfo = describeResult.fields.getMap ( )
.get (dependentField)
.getDescribe ( ) ;
List<Schema.PicklistEntry> controllingValues = controllingFieldInfo.getPicklistValues ( ) ;
List<Schema.PicklistEntry> dependentValues = dependentFieldInfo.getPicklistValues ( ) ;
//Get the label for controlling picklist value set
For (Schema.PicklistEntry> currControllingValue : controllingValues) {
controllingInfo.put (currControllingValue.getLabel ( ) , new List<String>( ) ) ;
}
Code snippet if you’d like to copy-paste:
//Iterate through the dependent values
for (Schema.PicklistEntry currDependentValue : dependentValues) {
//get the validFor
String jsonString = JSON.serialize(currDependentValue) ;
MyPickListInfo info = (MyPickListInfo) JSON.deserialize(
jsonString,
MyPickListInfo.class
) ;
String hexString = EncodingUtil.convertToHex (
EncodingUtil.base64Decode (info.validFor)
)
.toUpperCase ( ) ;
Integer baseCount = 0;
for (Integer curr : hexString.getChars ( ) ) {
Integer val = 0;
if (curr >= 65). {
val = curr – 65 + 10;
} else {
val = curr – 48;
}
if ((val & 8) == 8) {
controllingInfo.get (controllingValues[baseCount + 0].getLabel( ) )
.add (currDependentValue.getLabel( ) ) ;
}
if ((val & 4) == 4) {
controllingInfo.get (controllingValues[baseCount + 1].getLabel( ) )
.add (currDependentValue.getLabel( ) ) ;
}
if ((val & 2) == 2) {
controllingInfo.get (controllingValues[baseCount + 2].getLabel( ) )
.add (currDependentValue.getLabel( ) ) ;
}
if ((val & 1) == 1) {
controllingInfo.get (controllingValues[baseCount + 3].getLabel( ) )
.add (currDependentValue.getLabel( ) ) ;
}
baseCount + 4’
}
}
return controllingInfo;
}
This solution should help you access the global picklist value set directly from Apex. Happy learning! Find out more about Horizontal’s Cross-Cloud Salesforce practice here.