[SalesForce] I can’t get index of the row in a aura:iteration component in the client side controller

In my lightning component, I have a table with column that has a menu in it. The menu items are for edit and delete. I'm trying to find a way to get the row that was clicked on and so far everything thing I've found/tried hasn't worked. This is in a Summer 16 sandbox w/Locker Service enabled.

These approaches no longer work:

Here is the top level component:

<aura:component implements="flexipage:availableForAllPageTypes,force:appHostable,force:hasRecordId">
<c:AffiliationsList curRecordId="{!v.recordId}" />
<c:AffiliationDetails />

Here is the component that has the datagrid:

<aura:component implements="flexipage:availableForAllPageTypes,force:appHostable" controller="AffiliationController">
<ltng:require styles="/resource/SLDS103/assets/styles/salesforce-lightning-design-system-ltng.min.css"/>

<aura:attribute name="curRecordId" type="String"/>
<aura:attribute name="afList" type="AffiliationWrapper[]"/>
<aura:attribute name="numAf" type="Integer" default="0"/>

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

<div class="slds">
    <div class="slds-card">
        <div class="slds-card__header slds-grid">
            <div class="slds-media slds-media--center slds-has-flexi-truncate">
                <div class="slds-media__figure">
                    <c:svg class="slds-icon slds-icon-standard-contact slds-icon--small" xlinkHref="/resource/SLDS103/assets/icons/standard-sprite/svg/symbols.svg#contact"/>
                </div>
                <div class="slds-media__body">
                    <h2 class="slds-text-heading--small slds-truncate">Affiliations ({!v.numAf})</h2>
                </div>
            </div>
        </div>
        <div class="slds-card__body">
            <table class="slds-table slds-table--bordered slds-table--striped slds-max-medium-table--stacked-horizontal">
                <thead>
                    <tr class="slds-text-heading--label">
                        <th class="slds-is-sortable" scope="col">
                            <div class="slds-truncate">Relationship
                                <button class="slds-button slds-button--icon-bare">
                                    <c:svg class="slds-button__icon slds-button__icon--small" xlinkHref="/resource/SLDS103/assets/icons/utility-sprite/svg/symbols.svg#arrowdown"/>
                                    <span class="slds-assistive-text">Relationship</span>
                                </button>
                            </div>
                        </th>
                        <th class="slds-is-sortable" scope="col">
                            <div class="slds-truncate">Status
                                <button class="slds-button slds-button--icon-bare">
                                    <c:svg class="slds-button__icon slds-button__icon--small" xlinkHref="/resource/SLDS103/assets/icons/utility-sprite/svg/symbols.svg#arrowdown"/>
                                    <span class="slds-assistive-text">Status</span>
                                </button>
                            </div>
                        </th>
                        <th class="slds-is-sortable" scope="col">
                            <div class="slds-truncate">Project
                                <button class="slds-button slds-button--icon-bare">
                                    <c:svg class="slds-button__icon slds-button__icon--small" xlinkHref="/resource/SLDS103/assets/icons/utility-sprite/svg/symbols.svg#arrowdown"/>
                                    <span class="slds-assistive-text">Project</span>
                                </button>
                            </div>
                        </th>
                        <th class="slds-is-sortable" scope="col">
                            <div class="slds-truncate">Sub-Project
                                <button class="slds-button slds-button--icon-bare">
                                    <c:svg class="slds-button__icon slds-button__icon--small" xlinkHref="/resource/SLDS103/assets/icons/utility-sprite/svg/symbols.svg#arrowdown"/>
                                    <span class="slds-assistive-text">Sub-Project</span>
                                </button>
                            </div>
                        </th>
                        <th class="slds-is-sortable" scope="col">
                            <div class="slds-truncate">Task
                                <button class="slds-button slds-button--icon-bare">
                                    <c:svg class="slds-button__icon slds-button__icon--small" xlinkHref="/resource/SLDS103/assets/icons/utility-sprite/svg/symbols.svg#arrowdown"/>
                                    <span class="slds-assistive-text">Task</span>
                                </button>
                            </div>
                        </th>
                        <th class="slds-is-sortable" scope="col">
                            <div class="slds-truncate">Notes
                                <button class="slds-button slds-button--icon-bare">
                                    <c:svg class="slds-button__icon slds-button__icon--small" xlinkHref="/resource/SLDS103/assets/icons/utility-sprite/svg/symbols.svg#arrowdown"/>
                                    <span class="slds-assistive-text">Notes</span>
                                </button>
                            </div>
                        </th>
                        <th class="slds-cell-shrink"></th>
                    </tr>
                </thead>
                <tbody>
                    <aura:iteration items="{!v.afList}" var="af" indexVar="idx">
                        <tr class="slds-hint-parent slds-has-flexi-truncate" id="{!idx}">
                            <td class="slds-truncate slds-cell-wrap" data-label="Relationship">{!af.relationship}</td>
                            <td class="slds-truncate" data-label="Status">{!af.status}</td>
                            <td class="slds-truncate slds-cell-wrap" data-label="Project">
                                <a >{!af.project}</a>
                            </td>
                            <td class="slds-truncate slds-cell-wrap" data-label="Sub-Project">{!af.subProject}</td>
                            <td class="slds-truncate slds-cell-wrap" data-label="Task">{!af.task}</td>
                            <td class="slds-truncate slds-cell-wrap" data-label="Notes">{!af.note}</td>
                            <td class="slds-cell-shrink" data-label="Actions">
                                <ui:button aura:id="edit" label="Edit" press="{!c.editAffiliation}"/>
                                <!-- <ui:menu>
                                    <ui:menuTriggerLink aura:id="trigger" title="more"/>
                                    <ui:menuList class="actionMenu" aura:id="actionMenu">
                                        <ui:actionMenuItem aura:id="edit" label="Edit" click="{!c.editAffiliation}"/>
                                        <ui:actionMenuItem aura:id="delete" label="Delete" click="{!c.deleteAffiliation}"/>
                                    </ui:menuList>
                                </ui:menu> -->
                            </td>
                        </tr>
                    </aura:iteration>
                </tbody>
            </table>
        </div>
    </div>
</div>

Here is the controller:

({
    doInit : function(component, event, helper) {
        helper.loadAffiliations(component, event);
    },
    editAffiliation : function(component, event, helper) {
        helper.editRecord(component, event);
    }
})

Here is the helper:

({
    loadAffiliations : function(cmp, ev) {
        var action = cmp.get("c.getAffiliations");
        action.setParams({
            "currentId": cmp.get("v.curRecordId")
        });
        action.setCallback(this, function(response) {
            var state = response.getState();
            if(state === "SUCCESS") {
                var affiliations = response.getReturnValue();
                cmp.set('v.numAf', affiliations.length);
                cmp.set('v.afList', affiliations);
            }
            else if (state === "ERROR") {
                console.log('errors', response.getError());
            }
        });
        $A.enqueueAction(action);
    },
    editRecord : function(cmp, ev) {
        var row = cmp.getEvent("editAffiliation");
        console.log('row', row);
    }
})

console.log('row', row); logs out as null.

Originally my approach was just to pull the indexVar and then I'd be set but that's when I started finding out that none of the old ways worked anymore.

In my function, I'm thinking I should be able to get the value via getSource() on the event, but so far I haven't been able to figure out what, if any, key holds that value. It seems there should be a way to get to the dataset. Is there anyway to get the value for data-index from the event? It appears that the Locker Service has blocked everything. Or is there another approach that would work better? Any suggestions?

Best Answer

I believe the Event driven mechanism is probably the right way to handle this,instead of relying on the dataset attributes on the DOM.Inorder to do so,you have to split the component into two parts:

1.AffiliationsList - (fetches the data) -> Parent Component

2.AffiliationsListItem - (displays each record,fires selected data for edit) -> Child component

AffiliationsList.cmp

<aura:component implements="flexipage:availableForAllPageTypes,force:appHostable" controller="AffiliationController">
<ltng:require styles="/resource/SLDS103/assets/styles/salesforce-lightning-design-system-ltng.min.css"/>

<aura:attribute name="curRecordId" type="String"/>
<aura:attribute name="afList" type="AffiliationWrapper[]"/>
<aura:attribute name="numAf" type="Integer" default="0"/>

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

<div class="slds">
    <div class="slds-card">
        <div class="slds-card__header slds-grid">
            <div class="slds-media slds-media--center slds-has-flexi-truncate">
                <div class="slds-media__figure">
                    <c:svg class="slds-icon slds-icon-standard-contact slds-icon--small" xlinkHref="/resource/SLDS103/assets/icons/standard-sprite/svg/symbols.svg#contact"/>
                </div>
                <div class="slds-media__body">
                    <h2 class="slds-text-heading--small slds-truncate">Affiliations ({!v.numAf})</h2>
                </div>
            </div>
        </div>
        <div class="slds-card__body">
            <table class="slds-table slds-table--bordered slds-table--striped slds-max-medium-table--stacked-horizontal">
                <thead>
                    <tr class="slds-text-heading--label">
                        <th class="slds-is-sortable" scope="col">
                            <div class="slds-truncate">Relationship
                                <button class="slds-button slds-button--icon-bare">
                                    <c:svg class="slds-button__icon slds-button__icon--small" xlinkHref="/resource/SLDS103/assets/icons/utility-sprite/svg/symbols.svg#arrowdown"/>
                                    <span class="slds-assistive-text">Relationship</span>
                                </button>
                            </div>
                        </th>
                        <th class="slds-is-sortable" scope="col">
                            <div class="slds-truncate">Status
                                <button class="slds-button slds-button--icon-bare">
                                    <c:svg class="slds-button__icon slds-button__icon--small" xlinkHref="/resource/SLDS103/assets/icons/utility-sprite/svg/symbols.svg#arrowdown"/>
                                    <span class="slds-assistive-text">Status</span>
                                </button>
                            </div>
                        </th>
                        <th class="slds-is-sortable" scope="col">
                            <div class="slds-truncate">Project
                                <button class="slds-button slds-button--icon-bare">
                                    <c:svg class="slds-button__icon slds-button__icon--small" xlinkHref="/resource/SLDS103/assets/icons/utility-sprite/svg/symbols.svg#arrowdown"/>
                                    <span class="slds-assistive-text">Project</span>
                                </button>
                            </div>
                        </th>
                        <th class="slds-is-sortable" scope="col">
                            <div class="slds-truncate">Sub-Project
                                <button class="slds-button slds-button--icon-bare">
                                    <c:svg class="slds-button__icon slds-button__icon--small" xlinkHref="/resource/SLDS103/assets/icons/utility-sprite/svg/symbols.svg#arrowdown"/>
                                    <span class="slds-assistive-text">Sub-Project</span>
                                </button>
                            </div>
                        </th>
                        <th class="slds-is-sortable" scope="col">
                            <div class="slds-truncate">Task
                                <button class="slds-button slds-button--icon-bare">
                                    <c:svg class="slds-button__icon slds-button__icon--small" xlinkHref="/resource/SLDS103/assets/icons/utility-sprite/svg/symbols.svg#arrowdown"/>
                                    <span class="slds-assistive-text">Task</span>
                                </button>
                            </div>
                        </th>
                        <th class="slds-is-sortable" scope="col">
                            <div class="slds-truncate">Notes
                                <button class="slds-button slds-button--icon-bare">
                                    <c:svg class="slds-button__icon slds-button__icon--small" xlinkHref="/resource/SLDS103/assets/icons/utility-sprite/svg/symbols.svg#arrowdown"/>
                                    <span class="slds-assistive-text">Notes</span>
                                </button>
                            </div>
                        </th>
                        <th class="slds-cell-shrink"></th>
                    </tr>
                </thead>
                <tbody>
                    <aura:iteration items="{!v.afList}" var="af" indexVar="idx">
                        <c:AffiliationsListItem afRec="{!v.af}"
                    </aura:iteration>
                </tbody>
            </table>
        </div>
    </div>
</div>
</aura:component/>

AffiliationsListController.js

({
    doInit : function(component, event, helper) {
        helper.loadAffiliations(component, event);
    },
    editAffiliation : function(component, event, helper) {
        helper.editRecord(component,event);
    }
})

AffiliationsListHelper.js

({
    loadAffiliations : function(cmp, ev) {
        var action = cmp.get("c.getAffiliations");
        action.setParams({
            "currentId": cmp.get("v.curRecordId")
        });
        action.setCallback(this, function(response) {
            var state = response.getState();
            if(state === "SUCCESS") {
                var affiliations = response.getReturnValue();
                cmp.set('v.numAf', affiliations.length);
                cmp.set('v.afList', affiliations);
            }
            else if (state === "ERROR") {
                console.log('errors', response.getError());
            }
        });
        $A.enqueueAction(action);
    },
    editRecord : function(cmp, ev) {
        var row = event.getParam("selectedAffliation");
        console.log('row', row);
    }
})

Assuming your component level event looks like this :

affiliationToEdit.evt

<aura:event type="COMPONENT" description="Affiliation To Edit Event">
    <aura:attribute name="selectedAffliation" type="Object"/>
</aura:event>

AffiliationsListItem.cmp

<aura:component>
    <aura:attribute name="afRec" type="Object"/>
    <aura:registerEvent name="appEvent" type="c:affiliationToEdit"/>

    <tr class="slds-hint-parent slds-has-flexi-truncate">
        <td class="slds-truncate slds-cell-wrap" data-label="Relationship">{!v.afRec.relationship}</td>
        <td class="slds-truncate" data-label="Status">{!v.afRec.status}</td>
        <td class="slds-truncate slds-cell-wrap" data-label="Project">
            <a >{!v.afRec.project}</a>
        </td>
        <td class="slds-truncate slds-cell-wrap" data-label="Sub-Project">{!v.afRec.subProject}</td>
        <td class="slds-truncate slds-cell-wrap" data-label="Task">{!v.afRec.task}</td>
        <td class="slds-truncate slds-cell-wrap" data-label="Notes">{!v.afRec.note}</td>
        <td class="slds-cell-shrink" data-label="Actions">
            <ui:button aura:id="edit" label="Edit" press="{!c.editAffiliationRecord}"/>
            <!-- <ui:menu>
            <ui:menuTriggerLink aura:id="trigger" title="more"/>
            <ui:menuList class="actionMenu" aura:id="actionMenu">
            <ui:actionMenuItem aura:id="edit" label="Edit" click="{!c.editAffiliation}"/>
            <ui:actionMenuItem aura:id="delete" label="Delete" click="{!c.deleteAffiliation}"/>
            </ui:menuList>
            </ui:menu> -->
        </td>
    </tr>
</aura:component>

AffiliationsListItemController.js

({  //Fires the event to the parent,to capture the selected affliation record.
    editAffiliationRecord : function(component, event, helper) {
        var event = component.getEvent("appEvent");
        event.setParams({
            'selectedAffliation':component.get("v.afRec")
        });
        event.fire();
    }
})
Related Topic