
Custom Dependent Picklist Field With lightning:select In Lightning Component
Hey guys, today in this post we are going to create a new updated version of Custom Dependent Picklist fields using ‘lightning:select‘ base component in salesforce.
Prerequisites : basic understanding of Lightning Component & apex Programming
Step 0 : Setup Picklist field dependency
In this post , first we have create 2 custom picklist fields on salesforce standard Contact object
Country__c & City__c
then set field dependency. here country is the controller field and city is the dependent field.
Step 1 : Create apex controller
[dependentPicklist_UpdateCtrl.apxc]
public class dependentPicklist_UpdateCtrl { @AuraEnabled public static Map<String, List<String>> getDependentMap(sObject objDetail, string contrfieldApiName,string depfieldApiName) { String controllingField = contrfieldApiName.toLowerCase(); String dependentField = depfieldApiName.toLowerCase(); Map<String,List<String>> objResults = new Map<String,List<String>>(); Schema.sObjectType objType = objDetail.getSObjectType(); if (objType==null){ return objResults; } Map<String, Schema.SObjectField> objFieldMap = objType.getDescribe().fields.getMap(); if (!objFieldMap.containsKey(controllingField) || !objFieldMap.containsKey(dependentField)){ return objResults; } Schema.SObjectField theField = objFieldMap.get(dependentField); Schema.SObjectField ctrlField = objFieldMap.get(controllingField); List<Schema.PicklistEntry> contrEntries = ctrlField.getDescribe().getPicklistValues(); List<PicklistEntryWrapper> depEntries = wrapPicklistEntries(theField.getDescribe().getPicklistValues()); List<String> controllingValues = new List<String>(); for (Schema.PicklistEntry ple : contrEntries) { String label = ple.getLabel(); objResults.put(label, new List<String>()); controllingValues.add(label); } for (PicklistEntryWrapper plew : depEntries) { String label = plew.label; String validForBits = base64ToBits(plew.validFor); for (Integer i = 0; i < validForBits.length(); i++) { String bit = validForBits.mid(i, 1); if (bit == '1') { objResults.get(controllingValues.get(i)).add(label); } } } return objResults; } 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; } private static final String base64Chars = '' + 'ABCDEFGHIJKLMNOPQRSTUVWXYZ' + 'abcdefghijklmnopqrstuvwxyz' + '0123456789+/'; private static List<PicklistEntryWrapper> wrapPicklistEntries(List<Schema.PicklistEntry> PLEs) { return (List<PicklistEntryWrapper>) JSON.deserialize(JSON.serialize(PLEs), List<PicklistEntryWrapper>.class); } public class PicklistEntryWrapper{ public String active {get;set;} public String defaultValue {get;set;} public String label {get;set;} public String value {get;set;} public String validFor {get;set;} public PicklistEntryWrapper(){ } } }
- you don’t need to change anything in above apex classes.
Step 2 : Create Lightning Component
DependentPicklist.cmp
<aura:component implements="force:appHostable,flexipage:availableForAllPageTypes,flexipage:availableForRecordHome,force:hasRecordId,forceCommunity:availableForAllPageTypes,force:lightningQuickAction" access="global" controller="dependentPicklist_UpdateCtrl"> <!-- call doInit function on component load --> <aura:handler name="init" value="this" action="{!c.doInit}"/> <!-- aura attributes--> <aura:attribute name="listControllingValues" type="list" default="[]" description="to store controller field values"/> <aura:attribute name="listDependingValues" type="list" default="['--- None ---']" description="to store dependent field values"/> <aura:attribute name="depnedentFieldMap" type="map" description="map to store dependent values with controlling value"/> <aura:attribute name="bDisabledDependentFld" type="boolean" default="true"/> <aura:attribute name="objDetail" type="contact" default="{'sobjectType' : 'contact'}"/> <aura:attribute name="controllingFieldAPI" type="string" default="Country__c" description="store field API name of Controller field"/> <aura:attribute name="dependingFieldAPI" type="string" default="City__c" description="store field API name of dependent field"/> <!--Controller Field--> <lightning:layoutItem size="12" padding="around-small"> <lightning:select name="controllerFld" value="{!v.objDetail.Country__c}" label="Country" onchange="{!c.onControllerFieldChange}"> <aura:iteration items="{!v.listControllingValues}" var="val"> <option value="{!val}">{!val}</option> </aura:iteration> </lightning:select> </lightning:layoutItem> <!--Dependent Field--> <lightning:layoutItem size="12" padding="around-small"> <lightning:select name="dependentFld" value="{!v.objDetail.City__c}" label="City" disabled="{!v.bDisabledDependentFld}"> <aura:iteration items="{!v.listDependingValues}" var="val"> <option value="{!val}">{!val}</option> </aura:iteration> </lightning:select> </lightning:layoutItem> </aura:component>
DependentPicklistController.js
({ doInit : function(component, event, helper) { // get the fields API name and pass it to helper function var controllingFieldAPI = component.get("v.controllingFieldAPI"); var dependingFieldAPI = component.get("v.dependingFieldAPI"); var objDetails = component.get("v.objDetail"); // call the helper function helper.fetchPicklistValues(component,objDetails,controllingFieldAPI, dependingFieldAPI); }, onControllerFieldChange: function(component, event, helper) { var controllerValueKey = event.getSource().get("v.value"); // get selected controller field value var depnedentFieldMap = component.get("v.depnedentFieldMap"); if (controllerValueKey != '--- None ---') { var ListOfDependentFields = depnedentFieldMap[controllerValueKey]; if(ListOfDependentFields.length > 0){ component.set("v.bDisabledDependentFld" , false); helper.fetchDepValues(component, ListOfDependentFields); }else{ component.set("v.bDisabledDependentFld" , true); component.set("v.listDependingValues", ['--- None ---']); } } else { component.set("v.listDependingValues", ['--- None ---']); component.set("v.bDisabledDependentFld" , true); } }, })
Check also : Custom Multi-Select Picklist In Lightning Component With Select2 jQuery Plugin
DependentPicklistHelper.js
({ fetchPicklistValues: function(component,objDetails,controllerField, dependentField) { // call the server side function var action = component.get("c.getDependentMap"); // pass paramerters [object definition , contrller field name ,dependent field name] - // to server side function action.setParams({ 'objDetail' : objDetails, 'contrfieldApiName': controllerField, 'depfieldApiName': dependentField }); //set callback action.setCallback(this, function(response) { if (response.getState() == "SUCCESS") { //store the return response from server (map<string,List<string>>) var StoreResponse = response.getReturnValue(); // once set #StoreResponse to depnedentFieldMap attribute component.set("v.depnedentFieldMap",StoreResponse); // create a empty array for store map keys(@@--->which is controller picklist values) var listOfkeys = []; // for store all map keys (controller picklist values) var ControllerField = []; // for store controller picklist value to set on lightning:select. // play a for loop on Return map // and fill the all map key on listOfkeys variable. for (var singlekey in StoreResponse) { listOfkeys.push(singlekey); } //set the controller field value for lightning:select if (listOfkeys != undefined && listOfkeys.length > 0) { ControllerField.push('--- None ---'); } for (var i = 0; i < listOfkeys.length; i++) { ControllerField.push(listOfkeys[i]); } // set the ControllerField variable values to country(controller picklist field) component.set("v.listControllingValues", ControllerField); }else{ alert('Something went wrong..'); } }); $A.enqueueAction(action); }, fetchDepValues: function(component, ListOfDependentFields) { // create a empty array var for store dependent picklist values for controller field var dependentFields = []; dependentFields.push('--- None ---'); for (var i = 0; i < ListOfDependentFields.length; i++) { dependentFields.push(ListOfDependentFields[i]); } // set the dependentFields variable values to store(dependent picklist field) on lightning:select component.set("v.listDependingValues", dependentFields); }, })
- check above code comments.
- You just need to change the object API Name/Type on line number 15.[DependentPicklist.cmp].
- And change dependent field and controller field API Names on line number 16 – 17.[DependentPicklist.cmp].
TestApp.app
<aura:application extends="force:slds"> <c:DependentPicklist/> <!-- here c: is org. default namespace prefix--> </aura:application>
want to create 3 level picklist field dependency ? check example here
Like our facebook page for new post updates.? & Don’t forget to bookmark this site for your future reference.
Let us know if it helps you 🙂
people also check : How to use SVG in Salesforce Lightning Component ?
15 comments
Hi,
Thanks a lot for this component. Its really helpful!
I need to store the values of the above component details along with another component values by clicking on save button. May I know how this can be achieved please!
Thanks in advance:)
One of the key component missing in Salesforce’s lightning library. Thanks
Hi Piyush,
Thanks for sharing!!
label size
Saved lot of my Time. Thanks
Hi Piyush,
This is great, thanks! How would you adapt this code to include two dependent picklist fields being controlled by the same controlling picklist field on the same form?
i copied the code and all done but i am not getting the values in both controlled and dependant field,
here i changed the field api names as country__ c and city__c,
still i am not getting the values.
can you please help me in this
What will happen if pick list has translation, always it will display in English.
How can I pass the value and the label of the picklist, because right now the label is only being obtained, but when I translate at the moment the insertion in salesforce throws me the error, that the value does not exist in the selection list, please help!
I want to create dependent picklist having three dependent columns and it should applies independently on multiple rows. It means picklist fields in Columns are dependent but picklist fields in rows are not dependent to each other .I use the code given in http://sfdcmonkey.com/2018/08/31/dependent-picklist-lightningselect-lightning-salesforce/ , but it makes rows also dependent on each other. Please help if any one has code for this.
This is my component code:
<aura:iteration items=”{!v.NewoperationalApproverData}” var=”OperationalAPProver” indexVar=”rowIndex”>
<tr class=”slds-text-title_caps”>
<td>
{!rowIndex + 1}
I want to create dependent picklist having three dependent columns and it should applies independently on multiple rows. It means picklist fields in Columns are dependent but picklist fields in rows are not dependent to each other .I use the code given in http://sfdcmonkey.com/2018/08/31/dependent-picklist-lightningselect-lightning-salesforce/ , but it makes rows also dependent on each other. Please help if any one has code for this.
The following is my code component:
<aura:iteration items=”{!v.NewoperationalApproverData}” var=”OperationalAPProver” indexVar=”rowIndex”>
<tr class=”slds-text-title_caps”>
<td>
{!rowIndex + 1}
Thanks for the article.
Very well explained. Solved my problem!
is it possible to change the lightning:select with lightning:radioGroup
how can i work with lightning:radioGroup ?
if we have the country and city having the text fields how to achieve the same functionality
<option value=“{!val}” selected=”{!val == v.parentValue}”>{!val}</option> – keeps the previous value for the controlling picklist but similar thing doesnt work for the dependent, any suggestions?
<option value=“{!val}” selected=”{!val == v.childValue}”>{!val}</option> – doesnt work