function readOnly(count){ }
Starting November 20, the site will be set to read-only. On December 4, 2023,
forum discussions will move to the Trailblazer Community.
+ Start a Discussion
knght4yshuaknght4yshua 

Maximum call stack size exceeded on InputSelect

Never received a final response to my last question... really need to get this one working.  Can someone help?

I am getting this error and I don't know why:
Action failed: ui:inputSelect$controller$valueChange [Maximum call stack size exceeded]

COMPONENT CODE:
<aura:component access="global" controller="DependentPicklistTestController">
    <aura:attribute name="object" type="String"/>
    <aura:attribute name="controllingField" type="String"/>
    <aura:attribute name="dependentField" type="String"/>
    <aura:attribute name="selectedValue" type="String"/>
    <aura:attribute name="fieldName" type="String"/>
    <aura:attribute name="selectedDependentOption" type="String"/>
    <aura:attribute name="isDependentDisable" type="Boolean" default="false"/>
    <aura:handler name="init" value="{!this}" action="{!c.loadOptions}" /> 
    
    <ui:outputText value="{!v.fieldName}"/>:&nbsp;&nbsp;&nbsp;<ui:inputSelect aura:id="picklistOptions" 
                                                                              disabled="{!v.isDependentDisable}" 
                                                                              class="slds-input" 
                                                                              labelClass="slds-form-element__label"
                                                                              value="{!v.selectedOption}"
                                                                              required="true"
                                                                              onError="{!c.handleError}"
                                                                              onClearErrors="{!c.handleClearError}"/>
</aura:component>

JS CONTROLLER CODE:
({
	loadOptions : function(component, event, helper) {      
        helper.getOptionsHp(component, component.get("v.object"), component.get("v.controllingField"), component.get("v.dependentField"), component.get("v.selectedValue"));
    }
})

JS HELPER CODE:
({
    /*
     * Function to get all picklist values for a controlling/dependent pair
     */
    
    getOptionsHp: function(component, obj, controllingField, dependentField, selectedValue) {
        var optionValues = [];  
        var action;
        
        if(dependentField == "NULL"){            
        	action = component.get("c.getTopLevelOptionsApx");
            action.setParams({ 
                'obj' : obj,
                'field' : controllingField});
        }
        else{       
        	action = component.get("c.getOptionsApx"); 
            action.setParams({
                'obj' : obj,
                'controllingField' : controllingField,
                'dependentField' : dependentField});
        }
        action.setCallback(this, function(response) {
            var state = response.getState();  
            if (state === "SUCCESS" && !$A.util.isEmpty(response.getReturnValue()) && !$A.util.isUndefined(response.getReturnValue())) {  
                var returnedValues = response.getReturnValue();
                component.set("v.optionsMap",returnedValues);
                
                optionValues.push({
                    class: "optionClass",
                    label: "--- None ---",
                    value: "--- None ---",
                    selected: true
                });
                
                if($A.util.isUndefined(selectedValue) || $A.util.isEmpty(selectedValue) || selectedValue == "NULL"){
                    for(var i = 0; i < returnedValues.length; i++){
                        optionValues.push({
                            class: "optionsClass",
                            label: returnedValues[i],
                            value: returnedValues[i]
                        })
                    }
                }
                else{
                    for(var i = 0; i < Object.values(returnedValues[selectedValue]).length; i++){
                        optionValues.push({
                            class: "optionsClass",
                            label: Object.values(returnedValues[selectedValue])[i],
                            value: Object.values(returnedValues[selectedValue])[i]
                        })
                    }
                }
                
                component.find("picklistOptions").set("v.options",optionValues);
            }
            else if(state === "ERROR"){
                ('A problem occurred: ' + JSON.stringify(response.error));
            }
        });
        
        $A.enqueueAction(action);
    }
})

If I comment out this line the error goes away, but then again so does the information I need!:
 
component.find("picklistOptions").set("v.options",optionValues);

​APEX CONTROLLER CODE:
public class DependentPicklistTestController {
    
    /*
     * Retrieve all controlling and dependent picklist options
     */
    
    @AuraEnabled
    public static Map<String,List<String>> getOptionsApx(String obj, String controllingField, String dependentField){        
        Map<String,List<String>> optionsMap = new Map<String,List<String>>();
        DependentPicklistController dpc = new DependentPicklistController();
        optionsMap = dpc.getOptions(obj, controllingField, dependentField);       
        return optionsMap;
    }
    
    /*
     * Retrieve all picklist options for top-level fields (those which have no dependencies)
     */
    
    @AuraEnabled
    public static List<String> getTopLevelOptionsApx(String obj, String field){    
        List<String> options = new List<String>();        
        Schema.SObjectType objectType = Schema.getGlobalDescribe().get(obj);
        Map<String, Schema.SObjectField> fieldMap = objectType.getDescribe().fields.getMap();        
        Schema.DescribeFieldResult fieldResults = fieldMap.get(field).getDescribe();
        List<Schema.PicklistEntry> ples = fieldResults.getPicklistValues();        
        for(Schema.PicklistEntry ple : ples){
            options.add(ple.getValue());    
        }        
        return options;
    }
}

Any help you can provide is greatly appreciated!

Thanks!
Best Answer chosen by knght4yshua
Alain CabonAlain Cabon
Hi,

There is the same basic error here:
https://developer.salesforce.com/forums/ForumsMain?id=9060G0000005amRQAQ

<aura:attribute name="selectedValue" type="String"/>
 value="{!v.selectedOption}"

Please fix this beginner's error first (that cannot work otherwise).

Is it solved now?

@Raj V: news from Adam Drissel 7?

He doesn't come back here but the solution is obvious for his problem.

All Answers

Raj VakatiRaj Vakati
Can you share the DependentPicklistController apex class as well .. 
Alain CabonAlain Cabon
Hi,

The code of DependentPicklistController is missing.
 
knght4yshuaknght4yshua
Gotcha.  Here it is:

DEPENDENT PICKLIST CONTROLLER:
/*
* The purpose of this class is to allow for access to and use of dependent picklists in Visualforce and/or Lightning pages. 
* Values for any picklist field in the UI are obtained simply from the Schema tables, but their relationship to any related
* controlling field are contained in a Base64 hash that needs to be deciphered to access and utilize.  
*/

public class DependentPicklistController {
    /*
	 * Method to convert the Base64 "validFor" values for dependent picklist options into actual text options
	 */
    
    public Map<String,List<String>> getOptions(String obj, String controllingField, String dependentField){
        
        // Base64 > Integer values Map
        
        Map<String, Integer> base64Codes = new Map<String,Integer> {
            'A' => 0,'B' => 1,'C' => 2,'D' => 3,'E' => 4,'F' => 5,'G' => 6,
            'H' => 7,'I' => 8,'J' => 9,'K' => 10,'L' => 11,'M' => 12,
            'N' => 13,'O' => 14,'P' => 15,'Q' => 16,'R' => 17,'S' => 18,
            'T' => 19,'U' => 20,'V' => 21,'W' => 22,'X' => 23,'Y' => 24,
            'Z' => 25,'a' => 26,'b' => 27,'c' => 28,'d' => 29,'e' => 30,
            'f' => 31,'g' => 32,'h' => 33,'i' => 34,'j' => 35,'k' => 36,
            'l' => 37,'m' => 38,'n' => 39,'o' => 40,'p' => 41,'q' => 42,
            'r' => 43,'s' => 44,'t' => 45,'u' => 46,'v' => 47,'w' => 48,
            'x' => 49,'y' => 50,'z' => 51,'0' => 52,'1' => 53,'2' => 54,
            '3' => 55,'4' => 56,'5' => 57,'6' => 58,'7' => 59,'8' => 60,
            '9' => 61,'+' => 62,'/' => 63};
                    
		// Get all values for the corresponding controlling and dependent fields
                
		Map<String,Schema.SObjectType> globalMap = Schema.getGlobalDescribe();
        Schema.SObjectType objectType = Schema.getGlobalDescribe().get(obj);
        Map<String, Schema.SObjectField> fieldMap = objectType.getDescribe().fields.getMap();
        
        Schema.DescribeFieldResult controllingFieldResults = fieldMap.get(controllingField).getDescribe();
        List<Schema.PicklistEntry> controllingPles = controllingFieldResults.getPicklistValues();
        
        Schema.DescribeFieldResult dependentFieldResults = fieldMap.get(dependentField).getDescribe();
        List<Schema.PicklistEntry> dependentPles = dependentFieldResults.getPicklistValues();
        
        List<PicklistEntryWrapper> dependentPleEntries = new List<PicklistEntryWrapper>();
        dependentPleEntries = (List<PicklistEntryWrapper>)JSON.deserialize(JSON.serialize(dependentPles), List<PicklistEntryWrapper>.class);
        
        Map<String,List<String>> binaryStrings = new Map<String,List<String>>();
        
        // Loop through the "validFor" values for each dependent picklist entry
        
        for(PicklistEntryWrapper dependentPle : dependentPleEntries){
            String base64Entry = dependentPle.validFor;
            Integer base64Length = base64Entry.length();
            String base64Value;
            Integer base64IntegerValue;
            Integer value32;
            Integer value16;
            Integer value8;
            Integer value4;
            Integer value2;
            Integer value1;
            String binaryString = '';
            List<String> binaryValues = new List<String>();
            
            // Loop through each value in the "validFor" data returned
            
            for(Integer i = 1; i <= base64Length; i++){
                
                // Get the Integer value for this "validFor" value in the loop using the Map above
                
                if(i < base64Length){
                    base64Value = base64Entry.subString(i-1,i);
                    base64IntegerValue = base64Codes.get(base64Value);
                }
                else{
                    base64Value = base64Entry.subString(i-1,base64Length);
                    base64IntegerValue = base64Codes.get(base64Value);
                }
                
                /* 
                 * Get Binary values for each integer; the statements below assign a value to each of the 6 bits in a Base64
                 * binary string; values of each bit in the 6-bit string are, from left to right, 32-16-8-4-2-1; the functions
                 * below determine whether the base64IntegerValue requires a 1 or a 0 in each bit position
                 */
                
                if(base64IntegerValue/32 >= 1){
                    value32 = 1;
                } 
                else{value32 = 0;}
                
                if((base64IntegerValue-(32*value32))/16 >= 1){
                    value16 = 1;
                } 
                else{value16 = 0;}
                
                if((base64IntegerValue-(32*value32)-(16*value16))/8 >= 1){
                    value8 = 1;
                } 
                else{value8 = 0;}
                
                if((base64IntegerValue-(32*value32)-(16*value16)-(8*value8))/4 >= 1){
                    value4 = 1;
                } 
                else{value4 = 0;}
                
                if((base64IntegerValue-(32*value32)-(16*value16)-(8*value8)-(4*value4))/2 >= 1){
                    value2 = 1;
                } 
                else{value2 = 0;}
                
                if((base64IntegerValue-(32*value32)-(16*value16)-(8*value8)-(4*value4)-(2*value2))/1 >= 1){
                    value1 = 1;
                } 
                else{value1 = 0;}
                
                // Add the string value of each bit value (0 or 1) as a list entry
                
                binaryValues.add(value32.format());
                binaryValues.add(value16.format());
                binaryValues.add(value8.format());
                binaryValues.add(value4.format());
                binaryValues.add(value2.format());
                binaryValues.add(value1.format());
            }
            
            // Add the complete set of binaryValues, the number of which is equivalent to the total number of controlling
            // field values, to a Map with the dependent picklist option as its key
            
            binaryStrings.put(dependentPle.label,binaryValues);
        }
        
        /* 
         * The final Map contains a key/value pair for each dependent picklist entry, the key being the label 
         * of the dependent picklist entry and the value being a list of 0's and 1's, which, when read from 
         * left to right, correspond to an "include" or "exclude" for the corresponding controlling value
         */ 
        
        Map<String,List<String>> optionsMap = new Map<String,List<String>>();
        
        for(Schema.PicklistEntry controllingOption : controllingPles){
            optionsMap.put(controllingOption.value,new List<String>());
        }
        
        for(String dependentOptionName : binaryStrings.keyset()){
            for(Integer i = 0; i < optionsMap.size(); i++){
                if(binaryStrings.get(dependentOptionName)[i] == '1'){
                    optionsMap.get(controllingPles[i].value).add(dependentOptionName);
                }
            }
        }
        
        return optionsMap;
    }
}

 
Alain CabonAlain Cabon
Hi,

The code of PicklistEntryWrapper is just missing now.
 
knght4yshuaknght4yshua
PICKLISTENTRYWRAPPER CODE:
public class PicklistEntryWrapper{    
    public 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;}
}

 
knght4yshuaknght4yshua
Alain, Raj,

Any updates?  Do you need any more of the code?
Raj VakatiRaj Vakati
Code is here .. Please modify as per the best practices ..
<aura:component access="global" controller="DependentPicklistTestController">
    <aura:attribute name="object" type="String"/>
    <aura:attribute name="controllingField" type="String"/>
    <aura:attribute name="dependentField" type="String"/>
    <aura:attribute name="selectedValue" type="String"/>
    <aura:attribute name="fieldName" type="String"/>
    <aura:attribute name="selectedDependentOption" type="String"/>
    <aura:attribute name="isDependentDisable" type="Boolean" default="false"/>
    <aura:handler name="init" value="{!this}" action="{!c.loadOptions}" /> 
    
    <ui:outputText value="{!v.fieldName}"/>:&nbsp;&nbsp;&nbsp;
    <ui:inputSelect aura:id="picklistOptions" 
                                                                              disabled="{!v.isDependentDisable}" 
                                                                              class="slds-input" 
                                                                              labelClass="slds-form-element__label"
                                                                               required="true"
                                                                              onError="{!c.handleError}"
                                                                              onClearErrors="{!c.handleClearError}"/>
</aura:component>



Helper .js 

 
({
    /*
     * Function to get all picklist values for a controlling/dependent pair
     */
    
    getOptionsHp: function(component, obj, controllingField, dependentField, selectedValue) {
        var optionValues = [];  
        var action;
        if(dependentField == "NULL"){            
        	action = component.get("c.getTopLevelOptionsApx");
            action.setParams({ 
                'obj' : obj,
                'field' : controllingField});
        }
        else{       
        	action = component.get("c.getOptionsApx"); 
            action.setParams({
                'obj' : obj,
                'controllingField' : controllingField,
                'dependentField' : dependentField});
        }
        action.setCallback(this, function(response) {
            var state = response.getState();  
            if (state === "SUCCESS" && !$A.util.isEmpty(response.getReturnValue()) && !$A.util.isUndefined(response.getReturnValue())) {  
                var returnedValues = response.getReturnValue();
                console.log('returnedValues-->>>'+returnedValues)
               // component.set("v.optionsMap",returnedValues);
                optionValues.push({
                    class: "optionClass",
                    label: "--- None ---",
                    value: "--- None ---",
                    selected: true
                });
               // if($A.util.isUndefined(selectedValue) || $A.util.isEmpty(selectedValue) ){
                 for ( var key in returnedValues ) {
                        optionValues.push({
                            class: "optionsClass",
                            label: key,
                            value: key
                      })
                }
                /*
                for(var i = 0; i < returnedValues.length; i++){
                      
                        console.log('----'+returnedValues[i]);
                        optionValues.push({
                            class: "optionsClass",
                            label: returnedValues[i],
                            value: returnedValues[i]
                      })
                    }
                    */
               // }
             /*   else{
                     
                    for(var i = 0; i < Object.values(returnedValues[selectedValue]).length; i++){
                        optionValues.push({
                            class: "optionsClass",
                            label: Object.values(returnedValues[selectedValue])[i],
                            value: Object.values(returnedValues[selectedValue])[i]
                        })
                    }
                  
                }
                */
                console.log(optionValues);
              var temoVal =  component.find("picklistOptions"); 
            //   temoVal.set("v.options",null);
                         temoVal.set("v.options", optionValues);

               // set("v.options",optionValues);
            }
            else if(state === "ERROR"){
                ('A problem occurred: ' + JSON.stringify(response.error));
          //      var optionValues1 = [];
            //     component.find("picklistOptions").set("v.options",optionValues1);
            }
        });
        
        $A.enqueueAction(action);
    }
})

 
Alain CabonAlain Cabon
Hi,

I just found that selectedOption is not defined as an attribute or use selectedValue instead of selectedOption
and that is the cause of your error.

Nothing serious but the effect is blocking.

1) Missing in the component:  <aura:attribute name="selectedOption" type="String"/>

or     value="{!v.selectedValue}"  

2) Not an error below but: console.log seems missing.

   else if(state === "ERROR"){
                console.log('A problem occurred: ' + JSON.stringify(response.error));
    }

3) Some semicolons are missing sometime (not a error either and allowed with javascript that will add them automatically internally but it is sometime dangerous)

optionValues.push({
                           class: "optionsClass",
                           label: Object.values(returnedValues[selectedValue])[i],
                            value: Object.values(returnedValues[selectedValue])[i]
   })  ;


Finally, there is a minor error (selectedValue instead of selectedOption or vice-versa)
Alain CabonAlain Cabon
Hi,

There is the same basic error here:
https://developer.salesforce.com/forums/ForumsMain?id=9060G0000005amRQAQ

<aura:attribute name="selectedValue" type="String"/>
 value="{!v.selectedOption}"

Please fix this beginner's error first (that cannot work otherwise).

Is it solved now?

@Raj V: news from Adam Drissel 7?

He doesn't come back here but the solution is obvious for his problem.
This was selected as the best answer