Sorting objects/columns with multiple fields AngularJS using HTML template binding and javaScript

Sorting in the tabular data is very common task. If you are not using the ui-grid and using other component which doesn’t provide the inbuilt sorting feature, then you need to do some additional work for the sorting. Suppose, I have a HTML table and using the simple ng-repeat directive. I am showing the employees data(name, age and department) in that table and want to sort data by the more than one columns.

<table>
    <thead>
      <th>Name</th>
      <th>Age</th>
      <th>Employee Code</th>
      <th>Department</th>
    </thead>
    <tbody>
      <tr ng-repeat="emp in employees">
        <td>{{emp.name}}</td>
        <td>{{emp.age}}</td>
        <td>{{emp.code}}</td>
        <td>{{emp.department}}</td>
      </tr>
    </tbody>
  </table>

See the controller data:

$scope.columns = ["name", "age", "code", "department"];

  $scope.employees = [{
    name: "David",
    age: 27,
    code: "E111",
    department: "HR"
  }, {
    name: "Harry",
    age: 36,
    code: "P112",
    department: "Production"
  }, {
    name: "Harry, Potter",
    age: 42,
    code: "H111",
    department: "HR"
  }, {
    name: "Kat, R",
    age: 25,
    code: "H125",
    department: "Marketting"
  }, {
    name: "Alena",
    age: 32,
    code: "P859",
    department: "Production"
  }];

There are two ways to implement sorting: (1) You can use the ‘orderBy’ filter in your HTML template binding or (2) you can use the $’filter’ service in the JavaScript.

Using ‘orderby’ in HTML template

<tr ng-repeat="emp in employees | orderBy:'name'">

If you want to sort by more than one field, you can pass the array of the fields to ‘orderBy’, see below.

<tr ng-repeat="emp in employees | orderBy:['name',"age","department"]">

You can also control their sorting order. Suppose if you want to sort first by the name, then by the age but in decending order(higher age should be come first) and finally by department.

<tr ng-repeat="emp in employees | orderBy:['name',"-age","department"]">

An expression can be optionally prefixed with + or – to control the sorting direction, ascending or descending.
There is another argument in ‘orderby’ expression(If you are using Angular 1.5.7 and above) : comparator. The comparator function used to determine the relative order of value pairs. If omitted, the built-in comparator will be used.

Using ‘$filter’ service in JavaScript

If you want to sort the collection of the objects at run time, Angular also provides this feature. We can use the ‘$filter’ service. such as:

var orderByExpression = ['name',"-age","department"];
var reverse = false;
 $scope.employees = $filter('orderBy')($scope.employees,orderByExpression, reverse);

You can set the ‘true’ for the reverse to reversing sorting order.

Sorting columns with multiple fields angularjs in javascript
Sorting columns with multiple fields angularjs in javascript

Complete Example

Below is the complete example where we are designing the html table using the ng-repeat directive. There are three drop-downs controls to select the columns for sorting. See the plunker of the this example

<body ng-controller="MainCtrl">
  <table>
    <thead>
      <th>Name</th>
      <th>Age</th>
      <th>Employee Code</th>
      <th>Department</th>
    </thead>
    <tbody>
      <tr ng-repeat="emp in employees">
        <td>{{emp.name}}</td>
        <td>{{emp.age}}</td>
        <td>{{emp.code}}</td>
        <td>{{emp.department}}</td>
      </tr>
    </tbody>
 
  </table>
  <h2>Select Order By</h2>
  <div>Select First Order by:
  <select ng-options="item for item in columns" ng-model="firstOrderBy">
    <option value="">-- select first orderby --</option>
  </select></div><div>
  Select Second Order by:
  <select ng-options="item for item in columns" ng-model="secondOrderBy">
    <option value="">-- select second orderby --</option>
  </select></div><div>
  Select Third Order by:
  <select ng-options="item for item in columns" ng-model="thirdOrderBy">
    <option value="">-- select third orderby --</option>
  </select></div>
  <button ng-click="sortBy()">Sort</button>
</body>

Your angular controller:

var app = angular.module('plunker', []);
 
app.controller('MainCtrl', function($scope, $filter) {
  $scope.name = 'World';
  $scope.columns = ["name", "age", "code", "department"];
 
  $scope.employees =  [{
     name: "David", age: 27, code: "E111",department: "HR"}, 
     {name: "Harry", age: 36,code: "P112", department: "Production"}, 
     {name: "Harry, Potter", age: 42,code: "H111", department: "HR"},
     {name: "Kat, R", age: 25, code: "H125", department: "Marketting"},
     {name: "Alena", age: 32, code: "P859", department: "Production"}];
 
  $scope.firstOrderBy = "name";
  $scope.secondOrderBy = "age";
  $scope.thirdOrderBy = "code";
 
  $scope.sortBy = function() {
    var orderByExpression = [];
    if ($scope.firstOrderBy) {
      orderByExpression.push($scope.firstOrderBy);
    }
    if ($scope.secondOrderBy) {
      orderByExpression.push($scope.secondOrderBy);
    }
    if ($scope.thirdOrderBy) {
      orderByExpression.push($scope.thirdOrderBy);
    }
    $scope.employees = $filter('orderBy')($scope.employees,orderByExpression, false);
  };
});

In the above example, we are using three arguments for the ‘orderBy’. If you are using the Angular 1.5.7 and above you can also use the forth argument for the comparator.