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
1542VeMan1542VeMan 

Generate Dynamic InputSelect components (and inputSelectOptions) from fieldSets

Most of the examples of generating dynamic pickist options assumes that there is a known inputSelect component to which to add them. However, when creating components from fieldsets, one has to determine in realtime that a field in the set is a picklist. Then we have to create that inputSelect dynamically, and then create the inputSelectOptions after generating the inputSelect component, then add the entire bundle to a dynamic form component. 

The component containing all of this looks ike this:
<aura:component controller="ltngController">
    <aura:attribute name="userId" type="String" /><!--used to find the Contact-->
    <aura:attribute name="contact" type="Contact"/>
    <aura:attribute name="fieldSetName" type="String"/>
    <aura:attribute name="fields" type="Object[]"/><!--custom FieldSetMember class-->
    <aura:attribute name="picklistValues" type="Object[]" /><!--custom picklistOptions class-->
    <aura:attribute name="form" type="Aura.Component[]"/><!--dynamic component where generated components will be placed-->

    <aura:handler name="init" value="{!this}" action="{!c.doInit}"/>
    <!--HTML and other Lightning components-->

    <div class="row">
            <div class="section">
                <div class="cell form">
                          {!v.form}   
                </div>
            </div>
        </div>
</aura:component
The JSController runs the doInit which calls the server and gets the fieldSet data. This data is moved into a custom FieldSetMember class whose properties are AuraEnabled. For picklists, a describe call gets the Picklist value for this field and stores them in a list of custom PicklistValues objects. All this and the Contact record is bundled into a wrapper object and sent back to the JSController callback method. 
Checking the Debug Log and the Chrome Inspector verifies that all the data is available in the component controller, so that's not the problem.

Next step is to dynamcially create the components to hold the fieldSetdata in a helper method called 'createForm'. When a picklist value is encountered, I run the following 
createForm : function(cmp) {
	var fields = cmp.get('v.fields');
        var obj = cmp.get('v.contact');
        for (var i = 0; i < fields.length; i++) {
            var field = fields[i];
            if (field.type == 'PICKLIST'){
                var picklistValues = cmp.get("v.picklistValues");//all values for all picklist fields
                $A.createComponent("ui:inputSelect",
                                              {"label":field.label,
                                               "aura:id":field.label,
                                               "value":obj[field.fieldName],
                                               "required":field.required},
                    function(newSelect){
                        if (newSelect.isValid()){ // loop through the values to create options
                            for (var i = 0; i < picklistValues.length; i++){
                                var pItem = picklistValues[i];
                                
                                if (pItem.fieldName == field.fieldPath){ //only create for values that 
                                                                         //match the field's options
                                    $A.createComponent("ui:inputSelectOption",
                                                                  {"label":pItem.ItemLabel,
                                                                   "text":pItem.ItemValue},
                                          function(newOption){
                                              if (obj[field.fieldName] == pItem.ItemValue)
                                                  newOption.set("v.value":true);
                                                         
                                                   // get the inputSelect component's options attribute
                                                  var options = newSelect.get("v.options");
                                                  options.push(newOption);
                                                  newSelect.set("v.options",options);
                                          });
                                }
                            }
                        }
                        // after all picklist options are created and pushed into the v.options 
                        // attribute of the created inputSelect component, it all gets pushed into 
                        // the main component's v.form.
                           var form = cmp.get("v.form");
                           form.push(newSelect);
                           cmp.set("v.form",form);
                    });
            }
        }
}

OK, so after checking with the debugger; statement, all of those components appear to be created correctly. However, when I run the process, the picklist fields appear, with the correct label, but the drop-down for each reveals no selectOptions, even though there is enough empty space in the dropdown to match the number of options that should be visible. Here is a screen show of the rendered page:

User-added image
Agai, looking at the inputSelectOptions using the debugger statement in the Chrome DevTools Inspector showed that even as they were being inserted into the inputSelect component's options list, they contained the expected data, and the inputSelect components are showing in the form tag alongside the other field types. 

But WHY do the values not appear????? Any help is appreciated

1542VeMan1542VeMan
Updatig the above code - all of this was working, but I'm finding that although the components are being created correctly, the HTML is not rendering the selectOptions. 

Here is the entire createForm method with notes as to what is happening:
createForm : function(cmp) {
		var fields = cmp.get('v.fields');
        var obj = cmp.get('v.contact');
        
        for (var i = 0; i < fields.length; i++) {
            var field = fields[i];
            var config = this.configMap[field.type.toLowerCase()];// configMap provides component stubs to non-picklist fields, but is not included here.
            debugger;
            if (config){
                if (field.type != 'PICKLIST'){ // non-picklist component creation is working
                    debugger;
                    config.attributes.label = field.label;
                    config.attributes.required = field.required;
                	config.attributes.value = obj[field.fieldPath];
                    config.attributes.fieldPath = field.fieldPath;
                    
                    
                    $A.createComponent(config.componentDef,config.attributes,function(newSelect){
                        if (newSelect.isValid()){
                            var form = cmp.get("v.form");
                            form.push(newSelect);
                            cmp.set("v.form",form);
                        }
                    });
                } else { // This is where picklist (inputSelect) components are generated
                    var picklistValues = cmp.get("v.picklistValues");
                    debugger;
                    $A.createComponent("ui:inputSelect",{"aura:id":field.label,"label":field.label,
                        "required":field.required,"value":obj[field.fieldpath]
                        },
                        function(newSelect){
                            if (newSelect.isValid()){
                                var offset = 0;
                                for (var j = 0; j < picklistValues.length; j++){
                                    var pItem = picklistValues[j];
                                    debugger;
                                    if (pItem.fieldName == field.fieldPath){
                                        debugger;
                                                                                
                                        $A.createComponent("ui:inputSelectOption",
                                                           {"label":pItem.ItemLabel,
                                                            "text":pItem.ItemValue},
                                        function(newOption){
                                            if (obj[field.fieldPath] == pItem.ItemValue){
                                                newOption.set("v.value",true);
                                            }
                                            	
                                            var options = newSelect.get("v.options");
                                            
                                            options.push(newOption);
                                            
                                            newSelect.set("v.options",options);
                                            
                                            //VERIFY SELECTOPTION CREATION - THIS IS WORKING
                                            /*options = newSelect.get("v.options");
                                            debugger;
                                            var x = options.length;
                                            debugger;
                                            var y = options[j - offset];
                                            debugger;
                                            var z = options[j - offset].get("v.label");
                                            var za = options[j - offset].get("v.value");
                                            debugger;*/
                                            // ALL OF THE ABOVE TEST VALUES ARE DISPLAYING WHEN COMMENTS REMOVED
                                    	});
                                    } else {
                                        offset++;
                                    }
                            	}
                            }
                            var form = cmp.get("v.form");
                            form.push(newSelect);
                            cmp.set("v.form",form);
                            debugger;
                            
                            // TEST FOR FORM COMPONENT, INPUTSELECTS IN FORM, SELECTOPTIONS IN INPUTSELECTS IN FORM
                            // form is being loaded with each newSelect creation
                            form = cmp.get("v.form");
                            var fl = form.length;
                            var index = 0;
                            for (index = 0;index < fl; index++){
                                var a = form[index];
                                debugger;
                                if (a.get("v.options") != null){// FOUND INPUTSELECT COMPONENT IN FORM
                                    var b = a.get("v.options");
                                    debugger;
                                    var c = b[0].get("v.label");// SELECTOPTION IS FOUND IN INPUTSELECT
                                    debugger;
                                    // THE INPUTSELECT AND ASSOCIATED OPTIONS ARE BEING CREATED AND LOADED INTO THE PAGE
                                    // SO WHY AREN'T THEY DISPLAYING????????
                                }
                            }
                        });
                    }
            	}
        	} 
    	}
Now looking at the HTML in the page:

Here is the HTML for the Last Name inputText component which is rendering
<div data-aura-rendered-by="433:0" class="uiInput uiInputText uiInput--default uiInput--input" data-aura-class="uiInput uiInputText uiInput--default uiInput--input">
    <label class="uiLabel-left form-element__label uiLabel" for="1:114;a" data-aura-rendered-by="428:0" data-aura-class="uiLabel">
        <span class="" data-aura-rendered-by="429:0">Last Name</span>
        <!--render facet: 431:0-->
        <!--render facet: 432:0-->
    </label>
    <input class=" input" type="text" aria-describedby="" placeholder="" id="1:114;a" data-aura-rendered-by="5:114;a" data-interactive-lib-uid="3">
</div>

And here is the HTML for the Gender inputSelect component. The options are coming up as undefined!!
<div data-aura-rendered-by="442:0" class="uiInput uiInputSelect uiInput--default uiInput--select" data-aura-class="uiInput uiInputSelect uiInput--default uiInput--select">
    <label class="uiLabel-left form-element__label uiLabel" for="9:114;a" data-aura-rendered-by="437:0" data-aura-class="uiLabel">
        <span class="" data-aura-rendered-by="438:0">Gender</span>
        <!--render facet: 440:0-->
        <!--render facet: 441:0-->
    </label>
    <select class=" select" size="1" aria-describedby="" id="9:114;a" data-aura-rendered-by="14:114;a" data-interactive-lib-uid="4">
        <!--render facet: 15:114;a-->
        <option label="" value="undefined"></option>
        <option label="" value="undefined"></option>
    </select>
</div>
OK, so as I showed in the Javascript, I am able to 'get' this select component and its options from the form component and see their values AFTER they have been loaded into the form component. So, they exist, but to the browser they come up as undefined.