Dynamic dependent picklists in Salesforce

One thing that comes up a lot in the in the #salesforce IRC channel is doing dynamic Visual Force driven off of picklists.  So, let’s buckle up and get to it.

Data Model

In this simple example we are going to make an extension to the case page.  On this page we are going to us a custom Product/Version object to display on the page.  The product list well be determined on the start/end date of the product.  And the version will be driven by the currently selected product. Product

  • Name – The name of the product
  • Currently_Supported__c – Formula based on StartDate__c and EndDate__c (Integer version of a boolean)
  • StartDate__c – The date the product should be shown (Rollup min from the version)
  • EndDate__c – The date the product should be hidden (Rollup max from the version)


  • Name – The name of the version
  • Currently_Supported__c – Formula based on StartDate__c and EndDate__c (Integer version of a boolean)
  • StartDate__c – The date the version should be shown
  • EndDate__c – The date the version should be hidden
  • Product__c – The product the version is related to

Apex Controller

public with sharing class ProductUtils {
    static public List<Product__c> getAllProducts(Boolean includeEOL) {
        //This is done since the formula field cannot return a boolean
        Integer currentlySupported = (includeEOL) ? 0 : 1;

        return [
            select Name
            from Product__c
            where Currently_Supported__c >= :currentlySupported
            order by Name

    public static List<Product__c> getAllProducts() {
        return getAllProducts(false);

    public static List<Version__c> getAllVersions(Id productId, Boolean includeEOL) {
        Integer currentlySupported = (includeEOL) ? 0 : 1;

        return [
            select Name,
            from Version__c
            where Currently_Supported__c >= :currentlySupported and
                Product__c = :productId
            order by Name

    public static List<Version__c> getAllVersions(Id productId) {
        return getAllVersions(productId, false);

These methods are simple util methods to get product information and version information

global with sharing class CaseEdit_ControllerExtension {
    private final Id recordId;
    private final Case record;
    private final ApexPages.StandardController controller;

    public Case_ControllerExtension(ApexPages.StandardController stdController) {
        this.controller = stdController;
        this.recordId = this.controller.getId();
        this.record = [
            select Product__c,
            from Case
            where Id = :this.recordId
            limit 1

    public List<SelectOption> getProductList() {
        List<SelectOption> products = new List<SelectOption>();
        products.add(new SelectOption('', '--None--'));

        for (Product__c p: ProductUtils.getAllProducts()) {
            products.add(new SelectOption(p.Id, p.Name));

        return products;

    public Id getProduct() {
        return this.record.Product__c;

    public void setProduct(Id productId) {
        this.record.Product__c = productId;

    public List<SelectOption> getVersionList() {
        List<SelectOption> versions = new List<SelectOption>();
        versions.add(new SelectOption('', '--None--'));

        if (record.Product__c != null) {
            for (Version__c v: ProductUtils.getAllVersions(getProduct())) {
                versions.add(new SelectOption(v.Id, v.Name));

        return versions;

    public Id getVersion() {
        return this.record.Version__c;

    public void setVersion(Id versionId) {
        this.record.Version__c = versionId;

    public PageReference doSave() {
        Case c = (Case) controller.getRecord();
        c.Product__c = this.record.Product__c;
        c.Version__c = this.record.Version__c;

        upsert c;

        return new PageReference('/'+c.Id);

The controller has the getters and setters for the product and version.  But most importantly the getters for productList and versionList.  The versionList is triggered off the record’s product.  The other part of this is that for whatever reason (I couldn’t find a good one) is the getRecord does not include the changes made to the Product__c and Version__c field, so you’ll need to set them by hand in the doSave method.

One thing to note is since this is all done in the controller extension and since get and set use the Id, the select list will have the correct thing set when editing an existing record.

Visual Force Page

<apex:page standardController="Case" extensions="CaseEdit_ControllerExtension" title="Case Edit" tabStyle="Case">
    <apex:form id="form">
        <apex:pageBlock title="Case Edit">
                <apex:commandButton action="{!doSave}" value="Save" />
                <apex:commandButton action="{!cancel}" value="Cancel" />
            <apex:pageBlockSection title="Case Information">
                <apex:inputField value="{!Case.Summary}" required="true" />
                    <apex:outputLabel for="productList" value="{!$ObjectType.Case.fields.Product__c.label}" />
                        <apex:selectList value="{!product}" title="Product" size="1" id="products">
                            <apex:selectOptions value="{!productList}" />
                            <apex:actionSupport event="onchange" rerender="versions" />
                    <apex:outputLabel for="versions" value="{!$ObjectType.Case.fields.Version__c.label}" />
                        <apex:selectList value="{!version}" title="Version" size="1" id="versions">
                            <apex:selectOptions value="{!versionList}" />

The key parts of this is that the actionRegion surrounds both the item changing (product) and the dependent item (version).  If you had a third picklist you wanted to trigger on you could add another actionSupport item and tell it to rerender that third list.


Dependent picklists are not very hard to do as long as you remember the actionRegion around both the source and target, and making sure to get the data from the picklist prior to upserting your record.

This entry was posted in Development, Salesforce and tagged , , , , , , , . Bookmark the permalink.
  • Malcolm Mackay

    Hi Patrick,

    I am trying something similar on an custom opportunity – I want to build a product picklist based upon certain criteria (fixed value based upon the type of opportunity created)

    Apologies in advance for any stupid questions – new to Apex but not programming.


  • You can do this with any thing that you want. The key takeaways from this are that you:

    1. Use custom Visualforce
    2. Wrap your list in an actionRegion
    3. Return a List<SelectOption> for your getter in your controller

    Feel free to jump into the IRC channel an the folks in there can help with any specific issue you have.

  • hareesh

    Dynamic dependent pick list using apex : i created one Location__c object in that i Created two Pick Lists Country__c and State__c in Country__c pick list i added India,pakistan valus and in state__c pick list i added Andrapradesh,Madhyapradesh,lohore,Quetta if i select a value as India from Country__c pick list in State__c only able to see Andrapradesh,Madhyapradesh if i select a value as pakistan from country_c picklist in state__c only able to see lohore,Quetta by using apex

  • I would need more data and some of your code to see what is going on here. Feel free to join the #salesforce IRC channel and I can try to help you, or post your problem on Stackexchange or the developer boards.

  • Jeremy James

    HI Patrick. Having watched your Salesforce MVP video on Entitlement management I must admit I was very happy to see you posting on another topic I am trying to solve on Salesforce. I am trying to create dynamic dependent pick-lists on the case with Category > Product Family > Issue.

    Let me explain the case use:

    Category: Functional
    Product: Tilt Sensor
    Issue: No readings

    Category can be: Output
    Product: Tilt Sensor
    Issue: Drifting Values
    Unexpected values

    I am very new to Salesforce & Apex so any pointers you could give me would be greatly appreciated!

  • You can continue to change these picklists as deep as you want. You would just repeat the same steps as above and just use the Product as the parent of Issue. So you’d re-render Issue when Product is changed