Programatically change sort option
Is there a function I can call that is the equivalent of clicking one of the columns names?
For instance, clicking a button outside of the table could call the function to change which column the sorting is based on.
My use case is that I have a UI outside the table that changes what data the table contains and it makes more sense for some data to be sorted by one column and others by a different one. I'd like to programatically change which column the table is sorted by when the user clicks to change the table data.
I'm hoping there is (or can eventually be) a better way, but I worked out a hacky way to do it. I tried not to alter angular-tablesort.js but I ended up having to add one line. Here's how I did it:
-
add tablesort's
setSortFieldto its scope by adding$scope.setSortField = this.setSortFieldtoangular-tablesort.jsafter the function is defined -
access the table's scope and current sort order in the desired controller by extracting it from the
tablesort:sortOrderevent. This will fire when the component mounts assuming one of your column heads has thets-defaultattribute:
let tableScope, currentSortOrder;
$scope.$on('tablesort:sortOrder', function(event, sortOrder) {
tableScope = event.targetScope;
currentSortOrder = sortOrder;
});
This is pretty un-angular... Tablesort should maybe have a service that lets you communicate between controllers? This also wouldn't work well on a page with multiple sorting tables
- Now to change the sort order, you just need to call
tableScope.setSortField(sortexpr, element, name, sortBy).
I wrote the following function to easily sort by a column given its zero-indexed number.
// first get the column sorting info after the table mounted
// cols is an array of objects containing the DOM element and ts-criteria of the each table head
const cols = angular.element('th').map(function(i, el) {
const element = angular.element(el);
const name = element.attr('ts-criteria');
return {element, name};
});
// then you can call this function to sort by a column
$scope.sortByColumn = function(whichCol, order) {
// order follows tablesort convention.
// descending => order=true
// ascending => order=false
const element = cols[whichCol].element;
const name = cols[whichCol].name;
let timesToSort = 0;
// descending needs to set sort field twice if not already on proper column
if (order && currentSortOrder.name !== name)
timesToSort++;
if (currentSortOrder.name !== name || currentSortOrder.order)
timesToSort++;
while (timesToSort--) tableScope.setSortField(name, element);
}
Now from your view you can have something like
<button ng-click='sortByColumn(3, true)'>Sort 4th column descending</button>
Obviously, the column must have a ts-criteria attribute set.
If you have more than one table on the page, then the indices will be off. However you can have cols only get the th tags of a specific table (angular.element('#specificTable th')). But you'll need to handle currentSortOrder and tableScope differently.
What do people think of this? Is there a better way to do it?