Fetch a dependent picklist value set for a controlling field in Apex

Image
Fetch a dependent picklist value set for a controlling field in Apex

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 fieldsString objectName = ‘opportunity’;//Define controlling picklist value fieldString controllingField = ‘category__c’ ;//Define dependent picklist value fieldString dependentField = ‘subcategory__c’ ;//Declare map variable to store list of dependent value for controlling fieldMap<String, List<String>> controllingInfo = new Map<String, List<String>>( ) ;//Get the type being dealt withSchema.SObjectType objType = Schema.getGlobalDescribe( ).get(objectName) ;Schema.DescribeSObjectResult  describeResult = objType.getDescribe ( ) ;//Get controlling field valuesSchema.DescribeFieldResult  controllingFieldInfo = describeResult.fields.getMap ( ).get (controllingField).getDescribe ( ) ;//Get dependent field valuesSchema.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 setFor (Schema.PicklistEntry>  currControllingValue  :  controllingValues)  {controllingInfo.put (currControllingValue.­getLabel ( ) , new List<String>( ) ) ;}

Code snippet if you’d like to copy-paste://Iterate through the dependent valuesfor  (Schema.PicklistEntry  currDependentValue  :  dependentValues)  {//get the validForString  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.