Pages

Sorting in Angular js controller (along with paging)

Considering the problem of sorting only a handful of items that are on the current page, I guess sorting using the "orderBy" filter inside ng-repeat tag is not a good idea. So the solution is to apply sorting in AngularJS controller and here is how you can do that.


<html>
<head>
    <title>Angular sort </title>
    <link rel="stylesheet" href="//netdna.bootstrapcdn.com/bootstrap/3.1.1/css/bootstrap.min.css">
    <script src="http://code.angularjs.org/1.4.8/angular.js"></script>
    <script src="http://code.angularjs.org/1.4.8/angular-resource.js"></script>
    <script src="http://angular-ui.github.io/bootstrap/ui-bootstrap-tpls-0.11.0.js"></script>
    <script>

     var app = angular.module('MyForm', ['ui.bootstrap', 'ngResource']);
     app.controller('myCtrl', function ($scope, $filter) {
       $scope.predicate = 'name';
       $scope.reverse = true;
       $scope.currentPage = 1;
       $scope.order = function (predicate) {
           $scope.reverse = ($scope.predicate === predicate) ? !$scope.reverse : false;
           $scope.predicate = predicate;
           $scope.students = $filter('orderBy')($scope.students, $scope.predicate, $scope.reverse);
       };
       $scope.students = [
         { name: 'Kevin', age: 25, city: 'a' },
         { name: 'John', age: 30, city: 'b' },
         { name: 'Laura', age: 28, city: 'ba' },
         { name: 'Joy', age: 15, city: 'd' },
         { name: 'Mary', age: 28, city: 'c' },
         { name: 'Peter', age: 95, city: 'fe' },
         { name: 'Bob', age: 50, city: 'g' },
         { name: 'Erika', age: 27, city: 'e' },
         { name: 'Patrick', age: 40, city: 'ef' },
         { name: 'Tery', age: 60, city: 'aa' }
       ];
       $scope.totalItems = $scope.students.length;
       $scope.numPerPage = 5;
       $scope.paginate = function (value) {
            var begin, end, index;
            begin = ($scope.currentPage - 1) * $scope.numPerPage;
            end = begin + $scope.numPerPage;
            index = $scope.students.indexOf(value);
            return (begin <= index && index < end);
       };
     });
    </script>
    <style>
        tbody tr {
            background-color: rgb(243, 240, 240);
            color: #008b8b;
        }

        thead {
            background-color: darkgray;
        }
    </style>
</head>
<body ng-app="MyForm">
    <div ng-controller="myCtrl">
        <h3>List students</h3>
        <div class="container-fluid">
            <table class="table table-responsive">
                <thead>
                    <tr>
                        <th><a href="" ng-click="order('name')">Name</a></th>
                        <th><a href="" ng-click="order('age')"> Age</a> </th>
                        <th><a href="" ng-click="order('city')">City</a> </th>
                    </tr>
                </thead>
                <tbody>
                    <tr>
                        <td> <input type="text" ng-model="search.name" /></td>
                        <td> <input type="text" ng-model="search.age" /> </td>
                        <td><input type="text" ng-model="search.city" /> </td>
                    </tr>
                    <tr ng-repeat="user in students | filter:paginate| filter:search" ng-class-odd="'odd'">
                        <td>{{ user.name}}</td>
                        <td>{{ user.age}}</td>
                        <td>{{ user.city}}</td>
                    </tr>
                </tbody>
            </table>
            <pagination total-items="totalItems" ng-model="currentPage"
                        max-size="5" boundary-links="true"
                        items-per-page="numPerPage" class="pagination-sm">
            </pagination>
        </div>
    </div>
</body>
</html>  

There are few things that I would like to highlight in this code:-
  1. You need to inject filter in the controller as is done in this line "app.controller('myCtrl', function ($scope, $filter)".
  2.  Notice how the "orderBy" filter is applied inside the "$scope.order" method to apply ordering of items specified by the predicate. Here the items in "$scope.students" are sorted based on the field specified by "$scope.predicate" and sorting direction specified by "$scope.reverse" parameter.
  3. So now since the sorting is done by the order method that is called on the click event of table headers therefore we don't need to apply orderBy filter in the "ng-repeat" tag.