36

Context

This question has been asked before in the past and I've found several discussions of it here on StackExchange and elsewhere (links below to pages I've found in my research).

So far I'm not satisfied with any of the answers I've seen, and wanted to create this question just to poll the crowd one more time in case anything has changed in recent history that now makes this solvable.

The Problem

The basic challenge is easy to describe: You can use Schema Describe to obtain a list of picklist values for a given picklist field. That's not hard to do.

Where it gets tricky is if you have RecordType in the mix and the picklist is now being partially restricted based on the RecordType. If a field has say, 10 possible choices, but a RecordType restricts those choices down to 6, let's say, how do I know which six fields are valid options for that field?

I want to obtain this information from inside an Apex class—this is the rub and what invalidates a lot of existing solutions to this problem.

Possible Solutions

  1. describeLayout()

    Picklist value information seems to be readily available in the describeLayout() API call. Now if you've been around for a while you know people have gotten clever and learned to do a callout to the SF API from inside an Apex class but this feels too heavyweight for this purpose. Bringing in that API wrapper library and doing one of those self-calls just to know the right picklist values...there has to be a better way. (If you don't know what I'm talking about you can find it here: https://github.com/financialforcedev/apex-mdapi)
  2. <apex:inputField>

    The inputField component is capable of all kinds of automagical stuff that isn't easily replicated, and this case is no exception. <apex:inputField> respects the RecordType and reduced set of values for the picklist field. Some folks have put together solutions that leverage this to reverse-engineer the list, in a way, by rendering inputField picklist selectors on a VisualForce page then pulling those values back off the HTML of the page. This is obviously a bit janky and requires the use of a VisualForce page.
  3. validFor?

    I'm not even sure this is a possible approach, I'm fairly convinced it's a red herring at this point. A comment by the user Christophe Vidal on one of the questions in my research list below suggests that somehow validFor can be used to solve this problem. Some enterprising folks have figured out that even though validFor isn't documented as a property on PicklistEntry in Apex, you can extract it by serializing an instance to JSON and back. Then you have to chop it up using some bit manipulation to determine possible values. The purpose of "validFor" is to help people determine the connections between picklist values between controlling and dependent fields. I don't see how this can be extrapolated out to RecordTypes influencing picklists but if it's possible please do point me in the right direction.
  4. Hardcode it

    Though I abhor this approach I feel it must be included to be fair and balanced. One strategy here that might work for your situation would be to just bake the subsets of values into your Apex. Or duplicate them somewhere like a CustomSetting and ask admins to maintain it alongside the RecordType restriction list.

Conclusion

I've been casting about for a few days now looking for a clean solution to this problem and really haven't found one. Since I actually have to solve this problem I will eventually be forced into one of the above options unless a more palatable one is presented by someone here (here's hoping!).

Since in my use case a VisualForce page is indeed involved I think I will likely go the "apex:inputField" route. Save me from that terrible fate, good StackExchangers!

Related Links and Discussions

  1. https://stackoverflow.com/questions/7810801/how-to-describe-enumerate-picklist-enties-valid-for-a-specific-record-type-in
  2. https://developer.salesforce.com/forums?id=906F00000008z44IAA
  3. http://titancronus.com/blog/2014/07/03/acquiring-dependent-picklists-in-apex-contd/
  4. https://success.salesforce.com/ideaView?id=08730000000bhbwAAA
  5. https://developer.salesforce.com/forums/?id=906F00000008nNrIAI
  6. https://stackoverflow.com/questions/8560522/salesforce-record-type-and-opportunity-stage-relationship-database-location
  7. https://success.salesforce.com/ideaView?id=08730000000l6O5AAI
  8. https://github.com/financialforcedev/apex-mdapi/issues/4
  • 3
    +1 for one of the best written questions in a while (and the use of "janky"). Given that the answer is contained in the metadata, I'd go with option 1 but I'll be interested to see what others come up with. Yes, the package looks big but is incredibly useful. Option 4 is the real "janky" one – cropredy Dec 31 '15 at 1:23
  • 1
    I've personally used option (1). Besides a few trivial quirks (the name field for leads/contacts, for one), it's fast, and hardly noticeable on most layouts. Use that option if you just want to get it done like, this week. Other options may be possible, but I wouldn't trust (2) or (3) if they seem hackish, and option (4) is just asking for heartache. It'd be lovely if they had an official way to get at validFor that was documented. – sfdcfox Dec 31 '15 at 2:39
11

You can make use the User Interface API to get picklist values based on record type, https://developer.salesforce.com/docs/atlas.en-us.uiapi.meta/uiapi/ui_api_resources_picklist_values.htm

However, you need to make a REST API call and set Remote Site Settings. Here is the sample code for that,

Http http = new Http();
HttpRequest request = new HttpRequest();
String shost = System.Url.getSalesforceBaseURL().toExternalForm();
String url = shost + '/ui-api/object-info/{objectApiName}/picklist-values/{recordTypeId}/{fieldApiName}';
request.setEndpoint(url);
request.setMethod('GET');

// set Authorization 
request.setHeader('Authorization', 'OAuth '+UserInfo.getSessionId());
HttpResponse response = http.send(request);

You need to replace {objectApiName}, {recordTypeId} and {fieldApiName} with appropriate values. If anyone found a better solution not mentioned in the lists, please update.

1

This method actually works well - it is a little codey up front but this can be put into a utility module and modified as you see fit but it is a workable solution if you pass in parameters to fit the recordType name value... I've implemented a similar instance in a utility class to do this and it uses "validFor" to get dependent values - which RecordType fits that

Get lists of dependent picklist options in Apex

  • I'd give this a upvote if you added more context / example to your approach. it seems very exciting. – Christian Szandor Knapp Feb 24 '18 at 15:13
1

If I had to do this, I would create a custom setting that contains two fields: the record type name (or developername, whatever you prefer), and the picklist value. This would allow you to store each picklist value with an associated record type name, and it is easily updated if picklist values change. Then in the apex code you can use standard custom setting methods to pull back all the picklist values that are associated with a specific record type name. This avoids hard-coding of picklist values in your apex class and also avoids tons of extra code in your class. This isn't perfect, but for expediency and simplicity sake, I would do it this way if I only had a couple of picklists where it was important for me to only get the values associated with a certain record type. This would work fine on a small scale. If for some reason you have a lot of code that is looking for multiple picklist values for recordtypes on multiple objects, this would probably not be feasible from a maintainability standpoint.

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

Not the answer you're looking for? Browse other questions tagged or ask your own question.