+ Start a Discussion
Matt Brown 71Matt Brown 71 

Lightning dataTable sortedDirection not working

I'm using lightning dataTable component.  But the sortedDirection only ever sorts one direction.  The sortDirection param never updates properly. Here is some code:
 
<aura:component implements="flexipage:availableForAllPageTypes" 
                controller="CrossSellActivityController"
                access="global">

  <!-- Attributes -->
  <aura:attribute name="activities" type="Array" />
  <aura:attribute type="String" name="sortedDirection" default="asc" />
  <aura:attribute name="columns" type="List" />

  <!-- Component DOM -->
  <div>
    <lightning:datatable keyField="id"
                         data="{!v.activities}"
                         columns="{!v.columns}"
                         sortedDirection="{!v.sortedDirection}"
                         onsort="{!c.updateColumnSorting}"
                         hideCheckboxColumn="true" />
  </div>

</aura:component>
Here is the column definition:
var columns = [
  { label: 'Program Key', fieldName: 'Program_Key__c', type: 'text', sortable: true },
  { label: 'Status', fieldName: 'Disposition__c', type: 'text', sortable: true },
  { label: 'User', fieldName: 'Username', type: 'text', sortable: true },
  { label: 'Asset', fieldName: 'Asset', type: 'text', sortable: true },
  { 
    label: 'Timestamp', 
    fieldName: 'CreatedDate', 
    type: 'date', 
    typeAttributes: {
      day: 'numeric',
      month: 'short',
      year: 'numeric',
      hour: '2-digit',
      minute: '2-digit',
      second: '2-digit',
      hour12: true
    },
    sortable: true
  }
];
component.set("v.columns", columns);
And where I console.log out the sortedDirection variable:
updateColumnSorting : function(component, event, helper) {
  var sortDirection = event.getParam('sortDirection');        
  component.set("v.sortedDirection", sortDirection);
  console.log('sortDirection: ', sortDirection);
},
The console.log always outputs 'asc' never flips to 'desc'.  I've even tried changing the definition to Boolean with no luck.
<aura:attribute type="Boolean" name="sortedDirection" default="false" />
I've also tried flipping it myself with a truthy check and setting it back on the sortedDirection attribute, but that doesn't work either.  Am I doing something wrong?


 
Best Answer chosen by Matt Brown 71
Khan AnasKhan Anas (Salesforce Developers) 
Hi Matt,

Greetings to you!

I don't have your complete code so I can't tell where exactly is the problem. However, you can refer to the below code which I have tested in my org and it is working fine. Kindly modify the code as per your requirement.

Component:
<aura:component controller="DataTableSortingC"
                implements="force:appHostable,flexipage:availableForAllPageTypes,flexipage:availableForRecordHome,force:hasRecordId,forceCommunity:availableForAllPageTypes,force:lightningQuickAction" access="global" >
    
    <aura:attribute type="Account[]" name="acctList"/>
    <aura:attribute name="mycolumns" type="List"/>
    <aura:attribute name="sortedBy" type="String" default="Name"/>
    <aura:attribute name="sortedDirection" type="String" default="asc"/>
    
    <aura:handler name="init" value="{!this}" action="{!c.doinit}"/>
    
    <lightning:datatable data="{!v.acctList}" 
                         columns="{!v.mycolumns}" 
                         keyField="id"
                         hideCheckboxColumn="true"
                         onsort="{!c.updateColumnSorting}"
                         sortedBy="{!v.sortedBy}"  
                         sortedDirection="{!v.sortedDirection}"/>
</aura:component>

Controller:
({
    doinit : function(component, event, helper) {
        component.set('v.mycolumns', [
            {label: 'Account Name', fieldName: 'Name', type: 'text', sortable: true},
            {label: 'Industry', fieldName: 'Industry', type: 'text', sortable: true},
            {label: 'Type', fieldName: 'Type', type: 'text', sortable: true}            
        ]);
        
        var action = component.get("c.fetchAccts");
        action.setCallback(this, function(response){
            var state = response.getState();
            if (state === "SUCCESS") {
                component.set("v.acctList", response.getReturnValue());
                helper.sortData(component, component.get("v.sortedBy"), component.get("v.sortedDirection"));
            }
        });
        $A.enqueueAction(action);
    },
    
    updateColumnSorting: function (cmp, event, helper) {
        var fieldName = event.getParam('fieldName');
        var sortDirection = event.getParam('sortDirection');
        cmp.set("v.sortedBy", fieldName);
        cmp.set("v.sortedDirection", sortDirection);
        helper.sortData(cmp, fieldName, sortDirection);
    }
})

Helper:
({
    sortData: function (cmp, fieldName, sortDirection) {
        var data = cmp.get("v.acctList");
        var reverse = sortDirection !== 'asc';
        data.sort(this.sortBy(fieldName, reverse))
        cmp.set("v.acctList", data);
    },
    
    sortBy: function (field, reverse, primer) {
        var key = primer ?
            function(x) {return primer(x[field])} :
        function(x) {return x[field]};
        reverse = !reverse ? 1 : -1;
        return function (a, b) {
            return a = key(a), b = key(b), reverse * ((a > b) - (b > a));
        }
    }
})

Apex:
public class DataTableSortingC {
    
    @AuraEnabled
    public static List < Account > fetchAccts() {
        return [ SELECT Id, Name, Industry, Type FROM Account LIMIT 10 ];
    }
}

I hope it helps you.

Kindly let me know if it helps you and close your query by marking it as solved so that it can help others in the future.

Thanks and Regards,
Khan Anas

All Answers

Khan AnasKhan Anas (Salesforce Developers) 
Hi Matt,

Greetings to you!

I don't have your complete code so I can't tell where exactly is the problem. However, you can refer to the below code which I have tested in my org and it is working fine. Kindly modify the code as per your requirement.

Component:
<aura:component controller="DataTableSortingC"
                implements="force:appHostable,flexipage:availableForAllPageTypes,flexipage:availableForRecordHome,force:hasRecordId,forceCommunity:availableForAllPageTypes,force:lightningQuickAction" access="global" >
    
    <aura:attribute type="Account[]" name="acctList"/>
    <aura:attribute name="mycolumns" type="List"/>
    <aura:attribute name="sortedBy" type="String" default="Name"/>
    <aura:attribute name="sortedDirection" type="String" default="asc"/>
    
    <aura:handler name="init" value="{!this}" action="{!c.doinit}"/>
    
    <lightning:datatable data="{!v.acctList}" 
                         columns="{!v.mycolumns}" 
                         keyField="id"
                         hideCheckboxColumn="true"
                         onsort="{!c.updateColumnSorting}"
                         sortedBy="{!v.sortedBy}"  
                         sortedDirection="{!v.sortedDirection}"/>
</aura:component>

Controller:
({
    doinit : function(component, event, helper) {
        component.set('v.mycolumns', [
            {label: 'Account Name', fieldName: 'Name', type: 'text', sortable: true},
            {label: 'Industry', fieldName: 'Industry', type: 'text', sortable: true},
            {label: 'Type', fieldName: 'Type', type: 'text', sortable: true}            
        ]);
        
        var action = component.get("c.fetchAccts");
        action.setCallback(this, function(response){
            var state = response.getState();
            if (state === "SUCCESS") {
                component.set("v.acctList", response.getReturnValue());
                helper.sortData(component, component.get("v.sortedBy"), component.get("v.sortedDirection"));
            }
        });
        $A.enqueueAction(action);
    },
    
    updateColumnSorting: function (cmp, event, helper) {
        var fieldName = event.getParam('fieldName');
        var sortDirection = event.getParam('sortDirection');
        cmp.set("v.sortedBy", fieldName);
        cmp.set("v.sortedDirection", sortDirection);
        helper.sortData(cmp, fieldName, sortDirection);
    }
})

Helper:
({
    sortData: function (cmp, fieldName, sortDirection) {
        var data = cmp.get("v.acctList");
        var reverse = sortDirection !== 'asc';
        data.sort(this.sortBy(fieldName, reverse))
        cmp.set("v.acctList", data);
    },
    
    sortBy: function (field, reverse, primer) {
        var key = primer ?
            function(x) {return primer(x[field])} :
        function(x) {return x[field]};
        reverse = !reverse ? 1 : -1;
        return function (a, b) {
            return a = key(a), b = key(b), reverse * ((a > b) - (b > a));
        }
    }
})

Apex:
public class DataTableSortingC {
    
    @AuraEnabled
    public static List < Account > fetchAccts() {
        return [ SELECT Id, Name, Industry, Type FROM Account LIMIT 10 ];
    }
}

I hope it helps you.

Kindly let me know if it helps you and close your query by marking it as solved so that it can help others in the future.

Thanks and Regards,
Khan Anas
This was selected as the best answer
Matt Brown 71Matt Brown 71
Thanks for your answer Khan,

Are you on Winter '18 by chance? I see the only difference between your known working code and mine is that you are doing client side sorting, and so you're also setting the sortedBy where I am not, I'm almost curious if the dataTable doesn't update the sortedDirection unless your also using the client side sorting and passing in sortedBy="{!v.sortedBy}" bit as well.  Though I've tried this already now that I think about it.
Khan AnasKhan Anas (Salesforce Developers) 
Hi Matt,

I am on Winter 19. According to Salesforce doc (https://developer.salesforce.com/docs/component-library/bundle/lightning:datatable/documentation):

To enable sorting of row data by a column label, set sortable to true for the column on which you want to enable sorting. Set sortedBy to match the fieldName property on the column. Clicking a column header sorts rows by ascending order unless the defaultSortDirection is changed, and clicking it subsequently reverses the order. Handle the onsort event handler to update the table with the new column index and sort direction.

There is no change for sorting columns in lightning:datatable in Winter 19 release.

I hope it helps you.

Kindly mark this as solved if the information was helpful.

Thanks and Regards,
Khan Anas
Matt Brown 71Matt Brown 71
Thanks again,

I was able to figure out a work around.  The fact that the onsort="{!c.updateColumnSorting}" was being called correctly was enough for me to maintain my own sortDirection attribute.  I'm doing serverside sorting so this still works for my use case.
<div>
    <lightning:datatable keyField="id"
                         data="{!v.activities}"
                         columns="{!v.columns}"
                         onsort="{!c.updateColumnSorting}"
                         hideCheckboxColumn="true" />
  </div>
updateColumnSorting : function(component, event, helper) {
  var sortBy = event.getParam('fieldName');
  var sortDirection = component.get("v.sortDirection") == 'asc' ? 'desc' : 'asc';        
        
  component.set("v.sortedBy", sortBy);
  component.set("v.sortDirection", sortDirection);
},
So I'm no longer relying on the event.getParam('sortedDirection'); which was never updating, I'm simply looking directly at the component attribute now. 

I'm going to mark your answer as accepted since what you sent was a good solution and a working example.  I appreciate your time.
 
Raj VakatiRaj Vakati
Refer this link link 

https://rajvakati.com/2018/02/18/usage-of-lightningdatatable/


 
sortedBy="{! v.sortedBy }"
                             sortedDirection="{! v.sortedDirection }"
                             defaultSortDirection="{! v.defaultSortDirection }"
                             onsort="{! c.updateColumnSorting }"

 
Sisodia SaurabhSisodia Saurabh
Hello Everyone,
I am trying to impelement the same - column sorting by referring this forum.
I am getting issue that  Lightning: datatable "Onsort" event is not firing, I am getting column names as text only , nothing else(like arrow or something) to click sorting event firing.

below is my code:
TestAccountComponent
    <aura:attribute name="sortedBy" type="String" default="LastName"/>
    <aura:attribute name="sortedDirection" type="String" default="asc"/>
     <aura:attribute name="defaultSortDirection" type="String"/>
<lightning:datatable minColumnWidth="400px" 
                             data="{! v.Contact }" 
                             columns="{! v.Columns }"  
                             keyField="Id" 
                             hideCheckboxColumn="true"  
                             onsort="{!c.updateColumnSorting}" 
                             sortedBy="{!v.sortedBy}" 
                             sortedDirection="{!v.sortedDirection}"
                             defaultSortDirection="{! v.defaultSortDirection }"/> 

Controller:

getContact : function(component, event, helper) {
        debugger;
        helper.getStatus(component);
        helper.getLeadSourceOpt(component);
        
        component.set("v.Columns", [
            {label:"FirstName", fieldName:"FirstName", type:"text"},
            {label:"LastName", fieldName:"LastName", type:"text"},
            {label:"Phone", fieldName:"Phone", type:"text"},
            {label:"Email", fieldName:"Email", type:"text"},
            {label:"Contact_Status__c", fieldName:"Contact_Status__c", type:"text"},
             {label:"LeadSource", fieldName:"LeadSource", type:"text"}
        ]);
        var rcdID = component.get("v.recordId");
        var action = component.get("c.fetchContactList"); 
        action.setParams({ 
            recordId : rcdID
    });
        action.setCallback(this, function(data) {
          var state = data.getState();
          if (state === "SUCCESS") {
           component.set("v.Contact", data.getReturnValue());
           helper.sortData(component, component.get("v.sortedBy"), component.get("v.sortedDirection"));
            }
    });        
$A.enqueueAction(action);
    },
updateColumnSorting : function (cmp, event, helper) {
        var fieldName = event.getParam('fieldName');
       // var sortDirection = event.getParam('sortDirection');
       var sortDirection = component.get("v.sortDirection") == 'asc' ? 'desc' : 'asc';
        cmp.set("v.sortedBy", fieldName);
        cmp.set("v.sortedDirection", sortDirection);
        helper.sortData(cmp, fieldName, sortDirection);
    }
    
Helper::
 sortData : function (cmp, fieldname, sortDirection) {
         debugger;
        var data = cmp.get("v.Contact");
        var reverse = sortDirection !== 'asc';
        data.sort(this.sortBy(fieldname, reverse))
        cmp.set("v.Contact", data);
    },
    sortBy : function (field, reverse, primer) {
        var key = primer ?
            function(x) {return primer(x[field])} :
            function(x) {return x[field]};
        reverse = !reverse ? 1 : -1;
        return function (a, b) {
            return a = key(a), b = key(b), reverse * ((a > b) - (b > a));
        }
    }

Apex class::
@AuraEnabled
    public static List<contact> fetchContactList(Id recordId)
    {
        system.debug('fetchContactList');
        return [Select id, FirstName, LastName, Phone, Email, Contact_Status__c, LeadSource from Contact where AccountId=:recordId];
    }

Thanks.
Saurabh Sisodia
kiran b sfdckiran b sfdc
Hi Saurabh ,

To get the sort arrows next to field name & fire the onsort action, add the sortable property to the field that you wish to sort. 
For example :
{label:"FirstName", fieldName:"FirstName", type:"text",sortable:true},

Regards,
Kiran.B
NehaaaNehaaa
@Khan Anas  
tried with same approach ,sort icon is visible ,value with which column to sort are visible in alerts(debufs),but data is not sorted.
Any idea what might be the issue?
 
Duncan Barr 2Duncan Barr 2
Hi Guys,

I know this question is quite old but I had this same problem and after playing with this for the last few days, I think I now understand what the problem was in the original post. It gets a bit confsuing, so here goes:

The short answer is that the original poster was not setting the sortedBy attribute on the table component.

The lightning:datatable has 4 relevant attributes:
  • sortedBy="{!v.sortedBy}"
  • defaultSortDirection="{!v.defaultSortDirection}"
  • sortedDirection="{!v.sortedDirection}"
  • onsort="{!c.handleSort}"
The table component behaves in diferent ways depending on a combination of these attributes:
  1. If the onsort attribute is not filled, nothing will happen.
    • ​​​​You have to define your own sort function. Without this, the table component just logs that it has been sorted. Don't worry though. This isn't as hard as it sounds. The comment by Khan Anas contains a simple sort function which you can also find here: Official Sort Example  (https://developer.salesforce.com/docs/component-library/bundle/lightning:datatable/example#lightningcomponentdemo:exampleDatatableSorting)(if that link ever breaks, just google "lightning:datatable", go to the docs example link and scroll down to the 'Sorting in Data Table' example. I've also included it below.
    • If the user clicks on a column to sort that wasn't previously sorted by, the table will use the defaultSortDirection attribute.
    • ​​​​​​In real terms, this means that if event.getParam('fieldName') does not equal component.get('v.sortedBy'), then event.getParam('sortDirection') will be set to component.get('v.defaultSortDirection')
    • Read the above slower and try it out in some experiments.
      • In other words, if you sort by column 1 and then sort again by column 2, the table will use the defaultSortDirection for sorting by column 2.
      • But if you sort by column 2 again, the table will alternate the sort direction... but only if you've either set both sortedDirection and sortedBy, or neither... which brings me to my next point.
  2. If you set sortedBy, you must set sortedDirection as well and vise versa.
    • ​​​​​​Just set these two attributes at the bottom of your handleSort function. That's the simple answer.
    • If you don't set either of these attributes explicitly, the component will automatically set them, but it doesn't know which column you sorted by, so you won't get an indicator arrow on the appropriate column. Also, it doesn't know that you've clicked the same column twice in a row, so it'll always sort using the defaultSortDirection (see point 2).
    • Technically, you can get away with using this method if you update the defaultSortDirection at the bottom of your handleSort function, but... don't do that. It's clunky and doesn't make sense, and whoever reads the code months down the track wil not like you very much - including yourself!
  3. Spellcheck your assignments!
    • This sounds simple but it confused me a LOT when I couldn't figure out why it wasn't working.
    • PLEASE NOTE: In particular, the event contains a sortDirection attribute, but the datatable component has a corresponding sortedDirection attribute. sort vs sorted.
  4. Make sure your component actually has the appropriate attributes, and that they're linked to the attributes on the datatable itself.
    • Otherwise setting them is pointless and plain won't work.

I understand that this is long winded, but honestly, I wish I knew all this two days ago. It's not very well explained in the documentation.

Finally, just to fully answer the original question, here's how you could have fixed your code:

Component File
<aura:component implements="flexipage:availableForAllPageTypes" 
                controller="CrossSellActivityController"
                access="global">

  <!-- Attributes -->
  <aura:attribute name="activities" type="Array" />
  <aura:attribute name="sortedBy" type="String" />
  <aura:attribute name="defaultSortDirection" type="String" default="asc" />
  <aura:attribute name="sortedDirection" type="String" default="asc" />
  <aura:attribute name="columns" type="List" />

  <!-- Component DOM -->
  <div>
    <lightning:datatable keyField="id"
                         data="{!v.activities}"
                         columns="{!v.columns}"
                         sortedBy="{!v.sortedBy}"
                         defaultSortDirection="{!v.defaultSortDirection}"
                         sortedDirection="{!v.sortedDirection}"
                         onsort="{!c.updateColumnSorting}"
                         hideCheckboxColumn="true" />
  </div>

</aura:component>

Columns Definition
// definition unchanged
var columns = [
  { label: 'Program Key', fieldName: 'Program_Key__c', type: 'text', sortable: true },
  { label: 'Status', fieldName: 'Disposition__c', type: 'text', sortable: true },
  { label: 'User', fieldName: 'Username', type: 'text', sortable: true },
  { label: 'Asset', fieldName: 'Asset', type: 'text', sortable: true },
  { 
    label: 'Timestamp', 
    fieldName: 'CreatedDate', 
    type: 'date', 
    typeAttributes: {
      day: 'numeric',
      month: 'short',
      year: 'numeric',
      hour: '2-digit',
      minute: '2-digit',
      second: '2-digit',
      hour12: true
    },
    sortable: true
  }
];
component.set("v.columns", columns);

Sorting Function
updateColumnSorting : function(component, event, helper) {
  var sortDirection = event.getParam('sortDirection');
  var sortedBy = event.getParam('fieldName');

  // log the sort direction to prove I'm right :P
  console.log('sortDirection: ', sortDirection);

  // sort using some helper method (the original OP didn't include their sort method so here's one that'll work)
  var data = component.get('v.activities'); // I'm assuming this is where the OP stored their data.
  data.sort( helper.compare(sortedBy, (sortDirection === 'asc' ? 1 : -1) ));

  // set the sortedBy and sortedDirection attributes to allow the table to keep track (note the spelling difference between sortDirection and sortedDirection).
  component.set("v.sortedBy", sortedBy);
  component.set("v.sortedDirection", sortDirection);
},
Helper Function
sortBy: function(field, reverse, primer) {
        // see https://developer.salesforce.com/docs/component-library/bundle/lightning:datatable/example#lightningcomponentdemo:exampleDatatableSorting
        
        // this just gets the value from appropriate column. x represents the row of the table and field represents the fieldName or the column you're sorting by
        var key = primer
            ? function(x) {
                  return primer(x[field]);
              }
            : function(x) {
                  return x[field];
              };

        // this figures out which order the two rows should go in when compared. It will return either -1, 0, or 1 and reorder the rows accordingly.
        return function(a, b) {
            a = key(a);
            b = key(b);
            return reverse * ((a > b) - (b > a));
        };
    }


Thanks for reading and I really hope it helps someone out,

Duncan
Duncan Barr 2Duncan Barr 2
*sigh* amendment to the above: I tried to highlight my changes in the code by bolding the text, but the site converted it to html < b >bold< b /> tags... so please remove those if you want to use this code.
Mohita KalraMohita Kalra
@Duncan : Hi , Could you please let me know if I can have default sorted order in my lightning datatable ? I dont want end user to sort, data should always be sorted ascending