Print this page

Multi-field dependency through picklist in visualforce page

Knowledge Article Number 000181251
Description Creating multi-field dependency on picklist in visualforce page.
Resolution

Building the dependent list boxes

This article will cover creating the objects, page and controller to implement the dependent picklists.

The objects at the core

The foundation for this new functionality is two custom objects. By using custom objects, you can allow users to add new values for the dependent picklists without having to go to the Builder. You can use a standard Force.com relationship to establish the dependency.

For this example, I chose to create custom objects for categories and features, with each category having a subset of features, as shown in the entity relationship diagram below. Defining the custom objects for these two entities is easy - simply create an object called Feature_Category, which would only contain a record name (for simplicity), and another called Feature, which would have a lookup relationship with Feature_Category. You could also define the relationship as a master-detail relationship, but this particular use case might call for categories to be merged, in which case you would want to delete a parent but leave the children around for reassignment.

For this example, these two custom objects are all you will need for the Visualforce pages and controller you will develop.

The Visualforce page

The next step is to create a Visualforce page to implement the dependent functionality.

The controlling picklist

Let's create the page with only the controlling picklist object on the page. The code for this part of the page is -<apex:page controller="DependentObjects" id="UseCaseDisplay" label="FeatureCategoryReport" >

  <apex:form>
    <apex:pageBlock title="Feature Selection" mode="edit" id="thePageBlock">
      <apex:pageBlockSection columns="1">
        <apex:pageblockSectionItem>
          <apex:outputLabel value="Feature Category:" for="category"/>
          <apex:selectList value="{!category}" size="1" id="category">
            <apex:selectOptions value="{!categories}"/>
          </apex:selectList>
        </apex:pageblockSectionItem>
      </apex:pageBlockSection>
    </apex:pageBlock>
  </apex:form>
</apex:page>

Most of this code consists of standard Visualforce tags -

  • The page tag, which also identifies the controller for the page, which will be discussed later in this article
  • The form tag, which is required for any page that will have an interaction with the controller during the life of the page
  • The pageBlockpageBlockSection and pageblockSectionItem tags, which indicate different portions of the page
  • The outputLabel, which associates label text with a particular item

The relevant object in this section of the code is the selectList object. You can see that this variable is bound to the value of the categoryfield in the controller. When the select list is initialized, the list of options come from the categories list in the controller.

The last relevant option in the selectList object is the size option. You can see that the size is set to the value 1. With this setting, aselectList object magically becomes a picklist - which makes sense, when you think about it. A pick list is nothing more than a way to simply show one choice from a list on the page.

The controlled picklist

The controlled, or dependent, picklist code looks a lot like the code for the controlling picklist -

<apex:outputLabel value="Feature:" for="features"/>
     <apex:selectList value="{!feature}" size="1" id="features" disabled="{!ISNULL(category)}">
         <apex:selectOptions value="{!features}"/>
     </apex:selectList>

This picklist includes binding to a data value, a list of values display, shown as a selectList, and a size of 1, to shape the display into the picklist look-and-feel. You can notice one additional attribute for this picklist.

There is a disabled attribute, which is set according to the return from an Apex function, ISNULL(). You indicate that the function is run in the Apex code with the ! preceding the function. The effect of this attribute is to disable this dependent picklist if the controlling picklist does not have a value. This functionality is exactly what you want the dependent picklist to display.

The Visualforce controller

The Visualforce page you just learned about presents the user interface. This example is one case where the UI doesn't really impress - it looks just like a pair of picklists that you could create without Visualforce. The controller supplies data access that also replicates what the user experiences with dependent picklists.

Let's look at the code for the controller in sections, to make it easier to follow.

Declaring the variables

You have to begin by declaring variables in the controller to handle the category and feature values, as shown in the code below -

public class DependentObjects {

    /* String value for the category */
    String category;

    /* String value for the feature */
    String feature;

    /* Getter for the category value */
    public String getCategory() { return this.category; }

    /* Setter for the category value */
    public void setCategory(String s) { this.category = s; }

    /* Getter for the feature value */
    public String getFeature() { return this.feature; }
 
    /* Setter for the feature value */
    public void setFeature(String s) { this.feature = s; }
}

Pretty standard stuff, but necessary to integrate with the Visualforce page.

Getting the controlling picklist values

The controller gets a little more interesting when you look at the getter function for the categories selectList, as shown below

    /* Getter which dynamically generates the categories from the Feature_Category__c object. */
    public List<SelectOption> getCategories() {
      List<SelectOption> optionList = new List<SelectOption>();
      /* Add a null option to force the user to make a selection. */
      optionList.add(new SelectOption('','- None -'));

      /* Loop through the feature_category__c records creating a selectOption
         for each result with the record ID as the value and the name as the label 
         displayed in the selectList */
      for (Feature_Category__c fc : [select name from Feature_Category__c order by Name]){
        optionList.add(new SelectOption(fc.id,fc.name));
      }
      return optionList;     
    }

You start by creating a new List object to hold the choices for the picklist. The first value for the list should be - None -, to give the user a representation that no value has been selected.

The next step is to use the custom object Feature_Category__c to populate the controlling picklist with values. You use a simple forloop to add the ID for the value and the Name field, which is displayed in the picklist.

Getting the dependent picklist values

The last piece of the code is for the picklists the getter function for the features dependent picklist.

    /* Getter which generates the options for the features selectList based on the current
       value of the selected category. If there is no value selected then only
       the null option should be returned. */
    
public List<SelectOption> getFeatures() {
      List<SelectOption> optionList = new List<SelectOption>();
      /* Add a null option to force the user to make a selection. */
       optionList.add(new SelectOption('', '- None -')); 

      /* If a category has been selected then query for the related values */
      if(category != NULL) {

        /* Loop over the related feature records for the given category 
           creating a selectOption with the value being the feature record ID
           and the label is the name of the feature. */
        for (Feature__c f : [select name from Feature__c f where f.Feature_Category__c = :category]){
          optionList.add(new SelectOption(f.id,f.name));
        }
      }
      return optionList;
    }

The structure of this function is just like the getter function for the controlling picklist. The only real difference is that you have a different SOQL statement in the for loop. This one gets values from the Feature__c custom object, limiting the choices added to the list to those features which are children of the selected category in the controlling picklist.

Making the page work

There is only one line of code missing in the page, but this code makes the whole page work properly. The key part of the dependent picklist is that you want to change the values in that picklist whenever the selected value for the controlling picklist changes.

With Visualforce, you can do this easily with a partial page refresh - a refresh that only affects a part of the page, in this case the values in the dependent picklist.

A single HTML tag makes this happen -

<apex:actionSupport event="onchange" rerender="features"/>

This tag goes after the selectOptions tag and before the closing selectList tag. The actionSupport tag points to a client-side event, a change in the value of the selectList, will cause the features section of the page to be re-rendered.

With this, your page and controller code is complete.

What's the advantage?

So it looks like dependent picklists, and it acts like dependent picklists. So, why did you do this all over again?

To reiterate the advantages of this solution from the first part of this article, this implementation of dependent picklists frees you from the need to go into the Builder to add any additional values. Additionally, you could add additional fields to either of the custom objects to expand the data associated with a particular list value.

You can also use the relationship between objects to query for picklist values and their dependencies through the Force.com Web Service API, which means you can implement the functionality you want outside of the native Force.com Builder functionality.

But just having dependent picklists is not really any kind of application. In the third part of this article, you will see how to use these picklists to dynamically create reports, as well as switching between reports and detail views on the same page.





promote demote