The number of base lightning component is increasing in each release. But there are still few missing area. One of them is Dependent picklist. So today we will create Dependent picklist using Lightning:select.
This is a dynamic component, we just need to pass object name and dependent and controlling field. It will give you selected values. So if in your org Country and State picklist is enable. You can use this component to create same for custom object and store the value.

First we will create the component
LightningDependentPicklistCmp.cmp
<aura:component controller="LightningDependentPicklistCmpController" implements="force:appHostable,flexipage:availableForAllPageTypes,flexipage:availableForRecordHome,force:hasRecordId" access="global" >
<aura:handler name="init" value="{!this}" action="{!c.doInit}" />
<!-- aura attributes-->
<aura:attribute name="parentList" type="list" default="[]" description=""/>
<aura:attribute name="childList" type="list" default="[]"/>
<aura:attribute name="pickListMap" type="map"/>
<aura:attribute name="disabledChildField" type="boolean" default="true"/>
<aura:attribute name="objectName" type="string" default="Account"/>
<aura:attribute name="parentFieldAPI" type="string" default="Active__c"/>
<aura:attribute name="childFieldAPI" type="string" default="CustomerPriority__c"/>
<aura:attribute name="parentFieldLabel" type="string" />
<aura:attribute name="childFieldLabel" type="string"/>
<aura:attribute name="parentValue" type="string" default=""/>
<aura:attribute name="childValue" type="string" default=""/>
<lightning:card title="Dependent Picklist Demo">
<!-- Controller Field -->
<lightning:layoutItem size="12" padding="around-small">
<lightning:select name="parentField" aura:id="parentField"
value="{!v.parentValue}"
label="{!v.parentFieldLabel}"
onchange="{!c.parentFieldChange}">
<aura:iteration items="{!v.parentList}" var="value">
<option value="{!value}">{!value}</option>
</aura:iteration>
</lightning:select>
</lightning:layoutItem>
<!--Dependent Field-->
<lightning:layoutItem size="12" padding="around-small">
<lightning:select name="childField"
value="{!v.childValue}"
label="{!v.childFieldLabel}"
disabled="{!v.disabledChildField}">
<aura:iteration items="{!v.childList}" var="value">
<option value="{!value}">{!value}</option>
</aura:iteration>
</lightning:select>
</lightning:layoutItem>
</lightning:card>
</aura:component>
LightningDependentPicklistCmpController.Js
({
doInit : function(component, event, helper) {
var action = component.get("c.getDependentPicklist");
action.setParams({
ObjectName : component.get("v.objectName"),
parentField : component.get("v.parentFieldAPI"),
childField : component.get("v.childFieldAPI")
});
action.setCallback(this, function(response){
var status = response.getState();
if(status === "SUCCESS"){
var pickListResponse = response.getReturnValue();
//save response
component.set("v.pickListMap",pickListResponse.pickListMap);
component.set("v.parentFieldLabel",pickListResponse.parentFieldLabel);
component.set("v.childFieldLabel",pickListResponse.childFieldLabel);
// create a empty array for store parent picklist values
var parentkeys = []; // for store all map keys
var parentField = []; // for store parent picklist value to set on lightning:select.
// Iterate over map and store the key
for (var pickKey in pickListResponse.pickListMap) {
parentkeys.push(pickKey);
}
//set the parent field value for lightning:select
if (parentkeys != undefined && parentkeys.length > 0) {
parentField.push('--- None ---');
}
for (var i = 0; i < parentkeys.length; i++) {
parentField.push(parentkeys[i]);
}
// set the parent picklist
component.set("v.parentList", parentField);
}
});
$A.enqueueAction(action);
},
parentFieldChange : function(component, event, helper) {
var controllerValue = component.find("parentField").get("v.value");// We can also use event.getSource().get("v.value")
var pickListMap = component.get("v.pickListMap");
if (controllerValue != '--- None ---') {
//get child picklist value
var childValues = pickListMap[controllerValue];
var childValueList = [];
childValueList.push('--- None ---');
for (var i = 0; i < childValues.length; i++) {
childValueList.push(childValues[i]);
}
// set the child list
component.set("v.childList", childValueList);
if(childValues.length > 0){
component.set("v.disabledChildField" , false);
}else{
component.set("v.disabledChildField" , true);
}
} else {
component.set("v.childList", ['--- None ---']);
component.set("v.disabledChildField" , true);
}
}
})
LightningDependentPicklistCmpController.cls
public with sharing class LightningDependentPicklistCmpController {
private static final String base64Chars = '' +
'ABCDEFGHIJKLMNOPQRSTUVWXYZ' +
'abcdefghijklmnopqrstuvwxyz' +
'0123456789+/';
@AuraEnabled
public static PicklistWrapper getDependentPicklist(String ObjectName, string parentField, string childField) {
Map<String,List<String>> pickListMap = new Map<String,List<String>>();
PicklistWrapper pw = new PicklistWrapper();
pw.pickListMap = pickListMap;
if (Schema.getGlobalDescribe().get(ObjectName) ==null || String.isBlank(parentField) || String.isBlank(ChildField)){
return pw;
}
Schema.sObjectType objType = Schema.getGlobalDescribe().get(ObjectName).newSObject().getSObjectType();
Map<String, Schema.SObjectField> objFieldMap = objType.getDescribe().fields.getMap();
if (!objFieldMap.containsKey(parentField) || !objFieldMap.containsKey(childField)){
return pw;
}
List<PicklistEntryWrapper> depEntries = (List<PicklistEntryWrapper>)JSON.deserialize(JSON.serialize(objFieldMap.get(ChildField).getDescribe().getPicklistValues()), List<PicklistEntryWrapper>.class);
List<String> controllingValues = new List<String>();
for (Schema.PicklistEntry ple : objFieldMap.get(parentField).getDescribe().getPicklistValues()) {
pickListMap.put(ple.getLabel(), new List<String>());
controllingValues.add(ple.getLabel());
}
for (PicklistEntryWrapper plew : depEntries) {
String validForBits = base64ToBits(plew.validFor);
for (Integer i = 0; i < validForBits.length(); i++) {
String bit = validForBits.mid(i, 1);
if (bit == '1') {
pickListMap.get(controllingValues.get(i)).add(plew.label);
}
}
}
pw.pickListMap = pickListMap;
pw.parentFieldLabel = objFieldMap.get(parentField).getDescribe().getLabel();
pw.childFieldLabel = objFieldMap.get(childField).getDescribe().getLabel();
return pw;
}
//Refer from here https://salesforce.stackexchange.com/questions/4462/get-lists-of-dependent-picklist-options-in-apex
public static String decimalToBinary(Integer val) {
String bits = '';
while (val > 0) {
Integer remainder = Math.mod(val, 2);
val = Integer.valueOf(Math.floor(val / 2));
bits = String.valueOf(remainder) + bits;
}
return bits;
}
public static String base64ToBits(String validFor) {
if (String.isEmpty(validFor)) return '';
String validForBits = '';
for (Integer i = 0; i < validFor.length(); i++) {
String thisChar = validFor.mid(i, 1);
Integer val = base64Chars.indexOf(thisChar);
String bits = decimalToBinary(val).leftPad(6, '0');
validForBits += bits;
}
return validForBits;
}
public class PicklistWrapper{
@AuraEnabled
public Map<String, List<String>> pickListMap;
@AuraEnabled
public String parentFieldLabel;
@AuraEnabled
public String childFieldLabel;
}
public class PicklistEntryWrapper{
public String active;
public String defaultValue;
public String label;
public String value;
public String validFor;
}
}
As this a dynamic component so it handle field label as well. You can use this component in your existing app easily.
Did you like this post or want to add anything let me know in comments section. Happy programming 🙂
why did u use base64 in this clss, does it it fail without base64 ?
Yes it is required, you want to check reference SFSE post.
Thank you its Really help full 🙂
Hi,
I am able to get the previous value using the below for controlling picklist field.
{!value}
But this doent work for dependent picklist field.
{!value}
Any suggestions?
Thanks
Same for me
………….controlling field value not present