Angular Custom Table Component Sorting

Home / Angular Custom Table Component Sorting

One of the features that I had not implemented in my newer Angular component is sorting. Today I decided to go ahead and tackle this feature. Since the latest version of Angular is out, I’ve decided to simply refer to it as Angular. AngularJS will be used to refer to the older v1.x.


In the old directive, the Array.prototype.sort is used to sort a displayed array. This method will be used going forward as it works well. The things that have to be integrated into the Angular Component are the click handlers and classes for display.

Starting with the way the HTML template changes, the click events and ngClass attribute are integrated like this:

<th *ngFor="let column of options.columns" (click)="sortHeaderClick(column.value)"
  [ngClass]="{ 'sorting': isSorting(column.value), 'sorting_asc': isSortAsc(column.value), 'sorting_desc': isSortDesc(column.value) }">
  <span [innerHTML]="column.name"></span>
</th>

Looking at the sortHeaderClick handler, it will accept the name of the column that is clicked. If you’ll recall, the “CustomTableColumnDefinition” class defines a value. This is actually what the sort matching will be based upon. Maybe it’s a bit of a misnomer, then to use header name, but really, it could only depends on the binding in the ngFor.

sortHeaderClick(headerName: string) {
  if (headerName) {
    if (this.options.config.sortBy === headerName) {
      this.options.config.sortDirection = this.options.config.sortDirection === 'asc' ? 'desc' : 'asc';
    }
    this.options.config.sortBy = headerName;
    // Get the matching column
    var column: CustomTableColumnDefinition = this.options.columns.filter((column) => column.value === this.options.config.sortBy)[0];
    var isNumeric: bool = (column.filter && column.filter.indexOf("currency") != -1) || (column.isNumeric === true);
    this.sort(this.filteredData, this.options.config.sortBy, this.options.config.sortDirection, isNumeric);
  }
}

For completeness, the sort method is below. It is not different, other than to provide some TypeScript-centric syntax, than the sort method used in the older v1.x directive.

private sort(array: Array<any>, fieldName: string, direction: string, isNumeric: bool)
{
  var sortFunc = function (field, rev, primer) {
      // Return the required a,b function
      return function (a, b) {
          // Reset a, b to the field
          a = primer(pathValue(a, field)), b = primer(pathValue(b, field));
          // Do actual sorting, reverse as needed
          return ((a < b) ? -1 : ((a > b) ? 1 : 0)) * (rev ? -1 : 1);
      }
  };

  // Have to handle deep paths
  var pathValue = function (obj, path) {
      for (var i = 0, path = path.split('.'), len = path.length; i < len; i++) {
          obj = obj[path[i]];
      };
      return obj;
  };

  var primer = isNumeric ?
      function (a) {
          var retValue = parseFloat(String(a).replace(/[^0-9.-]+/g, ''));
          return isNaN(retValue) ? 0.0 : retValue;
      } :
      function (a) { return String(a).toUpperCase(); };

  this._isSorting = true;
  this._start = new Date().getTime();
  array.sort(sortFunc(fieldName, direction === 'desc', primer));
  this._end = new Date().getTime();
  var time = this._end - this._start;
  console.log('Sort time: ' + time);
  this._isSorting = false;
}

There are a few interesting things that this method does. You can see that the sortBy and sortDirection properties on the CustomTableConfig are updated to remember the user’s selections. Also, an array filter expression is used to find the specific column. This is necesary because numeric and non-numeric sorting are slightly different. Once it is determined if the column is numeric, or not, that information is passed to the sort method. The already received, via subscription, array of records is used rather than going back to the original observable. This keeps things in check.

Finally, the methods that are used to determine which column is currently being sorted, sort direction, and which column we’re sorting by have to be provided:

isSorting(name: string) {
  return this.options.config.sortBy !== name && name !== '';
};

isSortAsc(name: string) {
  console.log('isSortASc ' + name)
  var isSortAsc: bool = this.options.config.sortBy === name && this.options.config.sortDirection === 'asc';
  return isSortAsc;
};

isSortDesc(name: string) {
  var isSortDesc: bool = this.options.config.sortBy === name && this.options.config.sortDirection === 'desc';
  return isSortDesc;
};

The plunk below shows everything in action. The plunk does also include some of my other creations giving the appearance of a full application coming together. I think it helps illustrate how all of these components would work together in a real application. Next on my agenda is to add additional arbitrary filtering via filter pipes.

One thought on “Angular Custom Table Component Sorting”

Leave a Reply