I'd like to add 3 picklist fields to an Account object in the following manner:
- Parent multi-select Picklist field (let's call it ParentMultiSelectField__c)
- A dependent mutli-select Picklist field (let's call it ChildMultiSelectField__c) is dependent on the values in ParentMultiSelectField__c field
- And a third single picklist field (let's call it ChildSinglePiclistField__c) is also dependent on the values in ParentMultiSelectField__c field
For the sake of clarity, when I say dependent I mean that the values in the child fields will be filtered depending on the value(s) selected in the parent multi-select picklist.
My question is in 2 parts:
- Is this setup possible using standard salesforce point and click?
- If not, how do I implement this using visualforce and apex? (High level design should suffice)
Attribution to: Anup
Possible Suggestion/Solution #1
Safe Harbor: this is a really long answer...read at your own risk. Also, none of this sample code has been tested, this is just me stubbing it out in Notepad++.
This is not currently possible with standard Salesforce configuration, as multi-select picklists cannot be selected as the Controlling Field in a Field Dependency. So, you're definitely looking at a VisualForce solution; your approach here really depends on your requirements. Does it need to be easily configurable, or is it feasible to hardcode the dependencies in your controller?
If it's acceptable to hardcode the dependencies in your controller, then you'll probably want to set up maps of the dependencies to simplify your code (I use the word "simplify" loosely here)...
public class someController {
public String[] parentPicklistVal {public get; public set;}
public String[] childMultiPicklistVal {public get; public set;}
public String childSinglePicklistVal {public get; public set;}
// maps to hold your dependencies between picklists
private Map<String, List<String>> parentDepMap;
private Map<String, List<String>> childDepMap;
private String[] parentOpts = new String[] { 'parent option 1', 'parent option 2' };
private String[] childMultiOpts = new String[] { 'child multi 1', 'child multi 2', 'child multi 3' };
private String[] childSingleOpts = new String[] { 'child single 1', 'child single 2', 'child single 3' };
public someController() {
// init dependency maps
parentDepMap = new Map<String, List<String>>();
childDepMap = new Map<String, List<String>>();
// pick which child options to display for which parent value
parentDepMap.put(parentOpts[0], (new String[]{childMultiOpts[0], childMultiOpts[1]}));
parentDepMap.put(parentOpts[1], (new String[]{childMultiOpts[1], childMultiOpts[2]}));
// pick which single-select options to display for which child value
childDepMap.put(childMultiOpts[0], (new String[]{childSingleOpts[0], childSingleOpts[2]}));
childDepMap.put(childMultiOpts[1], (new String[]{childSingleOpts[1], childSingleOpts[2]}));
childDepMap.put(childMultiOpts[2], childSingleOpts); // or if you want to show them all?
}
public List<SelectOption> getParentPicklistOptions() {
List<SelectOption> selectOpts = new List<SelectOption>();
for ( String s : parentOpts )
selectOpts.add(new SelectOption(s, s));
return selectOpts;
}
public List<SelectOption> getChildMultiPicklistOptions() {
List<SelectOption> selectOpts = new List<SelectOption>();
if ( parentPicklistVal != null && parentPicklistVal.size() > 0 ) {
// build a set of values to avoid dupes, since there may be overlapping dependencies
Set<String> possibleOpts = new Set<String>();
for ( String val : parentPicklistVal )
possibleOpts.addAll(parentDepMap.get(val));
for ( String s : possibleOpts )
selectOpts.add(new SelectOption(s, s));
}
return selectOpts;
}
public List<SelectOption> getChildSinglePicklistOptions() {
List<SelectOption> selectOpts = new List<SelectOption>();
if ( childMultiPicklistVal != null && childMultiPicklistVal.size() > 0 ) {
// build a set of values to avoid dupes, since there may be overlapping dependencies
Set<String> possibleOpts = new Set<String>();
for ( String val : childMultiPicklistVal )
possibleOpts.addAll(childDepMap.get(val));
for ( String s : possibleOpts )
selectOpts.add(new SelectOption(s, s));
}
return selectOpts;
}
public PageReference actionUpdatePicklistVals() {
// this doesn't really need to do anything, since the picklists should be updated when their getters call after returning
return null;
}
}
And then your VF page...
<apex:page controller="someController">
<apex:form>
<apex:outputPanel id="panel1">
<apex:selectList value="{!parentPicklistVal}" multiselect="true" size="3">
<apex:selectOptions value="{!parentPicklistOptions}" />
<apex:actionSupport event="onchange" action="{!actionUpdatePicklistVals}" rerender="panel1" />
</apex:selectList>
<apex:selectList value="{!childMultiPicklistVal}" multiselect="true" size="3">
<apex:selectOptions value="{!childMultiPicklistOptions}" />
<apex:actionSupport event="onchange" action="{!actionUpdatePicklistVals}" rerender="panel1" />
</apex:selectList>
<apex:selectList value="{!childSinglePicklistVal}" multiselect="false" size="1">
<apex:selectOptions value="{!childSinglePicklistOptions}" />
</apex:selectList>
</apex:outputPanel>
</apex:form>
</apex:page>
However, if this needs to be easily configurable, then you're looking at a custom object with a lookup relationship to itself. You can then query the dependencies and build the maps from them instead of hardcoding them. Just throwing some ideas out there, let's say this custom object uses a Name field for its value, a FieldDep__c field as a lookup to it's controlling value, and a WhichPicklist__c field to control which picklist it belongs to (for this I'll just say it's an integer with possible values of 1, 2, and 3).
public class someController {
public String[] parentPicklistVal {public get; public set;}
public String[] childMultiPicklistVal {public get; public set;}
public String childSinglePicklistVal {public get; public set;}
private Map<String, List<String>> parentDepMap;
private Map<String, List<String>> childDepMap;
public someController() {
FieldDep__c[] deps = [select id, name, fielddep__c, fielddep__r.name, whichpicklist__c from FieldDep__c order name asc];
// init the same maps that we used in the example above
parentDepMap = new Map<String, List<String>>();
childDepMap = new Map<String, List<String>>();
for ( FieldDep__c dep : deps ) {
if ( dep.whichpicklist__c == 1 ) {
// shouldn't really need to do anything here...
} else if ( dep.whichpicklist__c == 2 ) {
// add to the dependency map between the parent and child multi-select picklist
String parentVal = dep.fielddep__r.name;
if ( parentDepMap.containsKey(parentVal) )
parentDepMap.get(parentVal).add(dep.Name);
else
parentDepMap.put(parentVal, new String[]{dep.Name});
} else if (dep.whichpicklist__c == 3 ) {
// add to the dependency map between the child multi-select and child single-select picklist
String parentVal = dep.fielddep__r.name;
if ( childDepMap.containsKey(parentVal) )
childDepMap.get(parentVal).add(dep.Name);
else
childDepMap.put(parentVal, new String[]{dep.Name});
}
}
}
public List<SelectOption> getParentPicklistOptions() {
List<SelectOption> selectOpts = new List<SelectOption>();
String[] parentOpts = parentDepMap.keySet();
for ( String s : parentOpts )
selectOpts.add(new SelectOption(s, s));
return selectOpts;
}
public List<SelectOption> getChildMultiPicklistOptions() {
List<SelectOption> selectOpts = new List<SelectOption>();
if ( parentPicklistVal != null && parentPicklistVal.size() > 0 ) {
// build a set of values to avoid dupes, since there may be overlapping dependencies
Set<String> possibleOpts = new Set<String>();
for ( String val : parentPicklistVal )
possibleOpts.addAll(parentDepMap.get(val));
for ( String s : possibleOpts )
selectOpts.add(new SelectOption(s, s));
}
return selectOpts;
}
public List<SelectOption> getChildSinglePicklistOptions() {
List<SelectOption> selectOpts = new List<SelectOption>();
if ( childMultiPicklistVal != null && childMultiPicklistVal.size() > 0 ) {
// build a set of values to avoid dupes, since there may be overlapping dependencies
Set<String> possibleOpts = new Set<String>();
for ( String val : childMultiPicklistVal )
possibleOpts.addAll(childDepMap.get(val));
for ( String s : possibleOpts )
selectOpts.add(new SelectOption(s, s));
}
return selectOpts;
}
public PageReference actionUpdatePicklistVals() {
// this doesn't really need to do anything, since the picklists should be updated when their getters call after returning
return null;
}
}
You would then want to populate FieldDep__c records from the top down so that you can add a lookup to the controlling value for each record.
I hope I didn't go too overboard with this! If I get a chance sometime today I'll put this together in an org to see how valid my code works, but it sounded like you were just looking for a push in the right direction (although this answer may have been slightly more than that...)
Attribution to: JCD
This content is remixed from stackoverflow or stackexchange. Please visit https://salesforce.stackexchange.com/questions/1249