Why is angular orderBy custom comparator not working?

Tom Shen picture Tom Shen · Jul 1, 2016 · Viewed 7.8k times · Source

I am trying to implement a custom comparator for the angular orderBy directive. As you can see in the code snippet, the custom comparator is being ignored (nothing logged from console.log) even though it should work according to the angular documentation for orderBy

I have tested the example code from the angular documentation on JsFiddle and it's not working either. Any ideas?

Answer

Tom Shen picture Tom Shen · Jul 1, 2016

I found the solution after some help from @morels : yes I should indeed return 1 and -1. But the main problem was that the comparator was being ignored. Apparently it is because this feature is only available to angular 1.5.7 and higher. I also needed to use the .split on the .value of the passed parameters of s1 and s2.

Here's the working solution in code snippet:

angular.module('orderByExample', [])
.controller('ExampleController', ['$scope', function($scope) {
  $scope.files = [
    {name: 'File1', size: '1.2 Mb'},
    {name: 'File2', size: '2.4 Kb'},
    {name: 'File3', size: '241 Bytes'},
    {name: 'File4', size: '2.0 Mb'},
    {name: 'File5', size: '16.1 Kb'}
  ];

  $scope.fileSizeComparator = function(s1, s2) {
    // split the size string in nummeric and alphabetic parts
    var s1Splitted = s1.value.split(" ");
    var s2Splitted = s2.value.split(" ");
    if (s1Splitted[1] === s2Splitted[1]) {
      // if size type is the same, compare the number
      return parseFloat(s1Splitted[0]) > parseFloat(s2Splitted[0]) ? -1 : 1;
    }
    // default : compare on size type Mb > Kb > Bytes
    return s1Splitted[1] > s2Splitted[1] ? -1 : 1;
  };
}]);
<script src="https://ajax.googleapis.com/ajax/libs/angularjs/1.5.7/angular.min.js"></script>
<div ng-app="orderByExample">
  <div ng-controller="ExampleController">
    <table>
      <tr>
        <th>Name</th>
        <th>Size</th>
      </tr>
      <tr ng-repeat="file in files | orderBy:'size':false:fileSizeComparator">
        <td>{{file.name}}</td>
        <td>{{file.size}}</td>
      </tr>
    </table>
  </div>
</div>