1

I am working on last few days on how to get the dependent picklist work when it is more than one record inside aura iteration. I apologize if this seems like I am asking for solution, but I am not and I did my homework and this is where I am stuck.

Here is the sample code:

ExampleApp.app:

<aura:handler name="init" value="{!this}" action="{!c.doInit}"/>

<aura:attribute name="dataArray" type="List"/>

<aura:attribute name="stateList" type="List"/>

<aura:attribute name="stateCityMap" type="Object"/>

<div aura:id="parent-aura-div-id">
    <table class="slds-table slds-table_bordered slds-table_col-bordered ">
        <thead>
            <tr>
                <th style="width:10px;">Row #</th>
                <th style="width:20px;">State</th>
                <th style="width:20px;">City</th>
            </tr>
        </thead>
        <tbody>
            <aura:iteration items="{!v.dataArray}" var="dataVar">
                <tr>
                    <td>{!dataVar.name}</td>
                    <td id="{! dataVar.name + '_state_td'}">
                        <select class="slds-select" 
                                id="{! dataVar.name + '_state'}" 
                                onchange="{!c.stateChanged}">
                            <aura:iteration items="{!v.stateList}" var="stateVar">
                                <option text="{!stateVar}" 
                                        selected="{! stateVar eq dataVar.state}"/>  
                            </aura:iteration>
                        </select>
                    </td>
                    <td id="{! dataVar.name +'_city_td'}">
                        <select class="slds-select" 
                                id="{! dataVar.name + '_city'}">
                        </select>
                    </td>
                </tr>
            </aura:iteration>               
        </tbody>
    </table>
</div>

ExampleAppController.js:

({

    doInit: function(component,event,helper){
        var dataArray = [];
        dataArray.push({name:'1',state:'MA',city:'Boston'},{name:'2',state:'NY',city:'NYC'});
        component.set('v.dataArray',dataArray);

        var stateList = [];
        stateList.push('MA','NY');
        component.set('v.stateList',stateList); 

        var stateCityMap = {};
        stateCityMap['MA'] = [];
        stateCityMap['MA'].push('Boston','Boston_X');
        stateCityMap['NY'] = [];
        stateCityMap['NY'].push('NYC','NYC_X');
        component.set('v.stateCityMap',stateCityMap);               
    },

    stateChanged: function(component,event,helper){
        var rowId = event.target.id.split('_')[0];
        var stateSelected = event.target.value;
        var citySelElem = component.find('parent-aura-div-id').getElement().querySelector('[id="'+rowId + '_city"]');
        var stateCityMap = component.get('v.stateCityMap');
        var cityArray = stateCityMap[stateSelected];
        var innerHTMLVar = '';
        for (var i = 0; i < cityArray.length; i++) {
            innerHTMLVar = innerHTMLVar + '<option value="' + cityArray[i]+ '">' +cityArray[i] +'</option>';  
        }
        citySelElem.innerHTML = innerHTMLVar;
    }
})

Output(I was able to get so far):

enter image description here

  1. As we can see in the gif above, I am stuck on how to populate the dependent field on the initial load.
  2. Once the controlling field is changed, I am able to change the options in the dependent picklist successfully.
  3. I feel this would have been solved easily, if we can iterate map collection with dynamic key but it is not possible.
  • why cannot you call Statechanged on do init? – Manjot Singh Jul 17 '17 at 18:26
  • Hmm. I didn't think of that but let me try. – javanoob Jul 17 '17 at 18:27
  • @ManjotSingh, I just tried and it is not working because when the init method is running, the DOM is not ready so I am not able to set options for city picklist. – javanoob Jul 17 '17 at 18:49
4

As I was looking into the documentation, I found this aura:render event and then with the below modifications, I was able to get it working.

Added the below line in the component:

<aura:handler name="render" value="{!this}" action="{!c.onRender}"/>

Added this new method in the controller:

onRender : function(component,event,helper){
        debugger;
        console.log('From Render method');
        var rootElem = component.find('parent-aura-div-id').getElement();
        var stateElemArray = rootElem.querySelectorAll('select[id$="_state"]');
        var stateCityMap = component.get('v.stateCityMap');
        var dataArray = component.get('v.dataArray');
        for (var i = 0; i < stateElemArray.length; i++) {
            console.log(stateElemArray[i].value);
            var rowId = stateElemArray[i].id.split('_')[0];
            var citySelElem = rootElem.querySelector('select[id$="' + rowId +'_city"]');
            var cityArray = stateCityMap[stateElemArray[i].value];
            var innerHTMLVar = '';
            for (var j = 0; j < cityArray.length; j++) {
                if(cityArray[j] == dataArray[rowId-1].city){
                    innerHTMLVar = innerHTMLVar + '<option value="' + cityArray[j]+ '" selected="true">'+ cityArray[j] +'</option>';    
                }else{
                    innerHTMLVar = innerHTMLVar + '<option value="' + cityArray[j]+ '">'+ cityArray[j] +'</option>';
                }
            }
            citySelElem.innerHTML = innerHTMLVar;           
        }
    }

I will keep this question open in case anyone finds a risk with handling render event.

UPDATE: Gist URL with the complete code : https://gist.github.com/sfdcnoob/c9bbd38771c2ff9946e4d7035b9ef2e1

  • 1
    I do think this is best Approach – Manjot Singh Jul 17 '17 at 18:55

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

Not the answer you're looking for? Browse other questions tagged or ask your own question.