[SalesForce] Client side sorting based on Parent Fields

Client-side sorting in Lightning Component, In my component I have Parent Records as well, so I need to sort based on Parent Records also.
Currently, I'm doing sorting on Server side but I want to do this on client side
I have used the code given here.

It seems sorting is not working on Parent Records.
How can we make client-side sorting work for Parent records as well?

Component:

<table class="slds-table slds-table--bordered slds-table--cell-buffer">
        <thead>
            <tr class="slds-text-title--caps">
      <th scope="col">
                    <div onclick="{!c.sortByAnnualRevenue}"
                         class="slds-truncate"
                         title="Account Name">
                        Annual Revenue
                        <aura:if isTrue="{!v.sortField=='AnnualRevenue'}">
                            <span>
                                <aura:if isTrue="{!v.sortAsc}">
                                    &#8593;
                                    <aura:set attribute="else">
                                        &#8595;
                                    </aura:set>
                                </aura:if>
                            </span>
                        </aura:if>
                    </div>
                </th>
                <th scope="col">
                    <div onclick="{!c.sortByParentName}"
                         class="slds-truncate"
                         title="Parent Name">
                        Parent Name
                        <aura:if isTrue="{!v.sortField=='Parent.Name'}">
                            <span>
                                <aura:if isTrue="{!v.sortAsc}">
                                    &#8593;
                                    <aura:set attribute="else">
                                        &#8595;
                                    </aura:set>
                                </aura:if>
                            </span>
                        </aura:if>
                    </div>
                </th>
            </tr>
        </thead>
        <tbody>
            <aura:iteration items="{!v.currentList}" var="record">
            <tr>
            <th data-label="Annual Revenue">
                        <div class="slds-truncate" title="{!record.AnnualRevenue}">
                            {!record.AnnualRevenue}
                        </div>
                    </th>
                    <th data-label="Annual Revenue">
                        <div class="slds-truncate" title="{!record.Parent.Name}">
                            {!record.Parent.Name}
                        </div>
                    </th>
                </tr>
            </aura:iteration>
        </tbody>
    </table>

Controller:

sortByAnnualRevenue: function(component, event, helper) {
        helper.sortBy(component, "AnnualRevenue");
},
sortByParentName: function(component, event, helper) {
        helper.sortBy(component, "Parent.Name");
}

Helper:

({
    sortBy: function(component, field) {
        var sortAsc = component.get("v.sortAsc"),
            sortField = component.get("v.sortField"),
            records = component.get("v.allAccounts");
        console.log('>>>before condition sortAsc.. '+sortAsc);
        console.log('>>>before condition sortField.. '+sortField);
        sortAsc = sortField != field || !sortAsc;
        console.log('>>>after condition sortAsc.. '+sortAsc);
        console.log('>>>after condition sortField.. '+sortField);
        records.sort(function(a,b){
            var t1 = a[field] == b[field],
                t2 = (!a[field] && b[field]) || (a[field] < b[field]);
            return t1? 0: (sortAsc?-1:1)*(t2?1:-1);
        });
        component.set("v.sortAsc", sortAsc);
        component.set("v.sortField", field);
        component.set("v.allAccounts", records);
        this.renderPage(component);
    },
    renderPage: function(component) {
        var records = component.get("v.allAccounts"),
            pageNumber = component.get("v.pageNumber"),
            pageRecords = records.slice((pageNumber-1)*10, pageNumber*10);
        component.set("v.currentList", pageRecords);
    }
})

Best Answer

That code wasn't designed to handle parent path, but the sort function could be updated to support this:

({
    sortBy: function(component, field) {
        var sortAsc = component.get("v.sortAsc"),
            sortField = component.get("v.sortField"),
            records = component.get("v.allAccounts"),
            fieldPath = field.split(/\./),
            fieldValue = this.fieldValue;
        sortAsc = sortField != field || !sortAsc;
        records.sort(function(a,b){
            var aValue = fieldValue(a, fieldPath),
                bValue = fieldValue(b, fieldPath),
                t1 = aValue == bValue,
                t2 = (!aValue && bValue) || (aValue < bValue);
            return t1? 0: (sortAsc?-1:1)*(t2?1:-1);
        });
        component.set("v.sortAsc", sortAsc);
        component.set("v.sortField", field);
        component.set("v.allAccounts", records);
        this.renderPage(component);     
    },
    fieldValue: function(object, fieldPath) {
        var result = object;
        fieldPath.forEach(function(field) {
            if(result) {
                result = result[field];
            }
        });
        return result;
    },
    renderPage: function(component) {
        var records = component.get("v.allAccounts"),
            pageNumber = component.get("v.pageNumber"),
            pageRecords = records.slice((pageNumber-1)*10, pageNumber*10);
        component.set("v.currentList", pageRecords);
    }
})

The only real difference is that we follow the object path until we find the final value or reach a null value. This should work for most practical types.