Willy Willy - 6 months ago 315
AngularJS Question

How to sort and filter all records in AngularJS that are paginated using UI Bootstrap Pagination

I'm doing client-side pagination using angular ui-bootstrap pagination to add paging to the list and then I'm getting a problem that the sorting and filtering process only sort and filter the data only in the current page.

Here is the code snippets in view to display the data:

<tr ng-repeat="reminderType in reminderTypes | filter: paginate | filter: searchText | orderBy:sortBy:sortDescending">
<td>
<a class="btn btn-sm btn-primary" ng-click="editReminderType(reminderType.ReminderTypeID)"><i class="glyphicon glyphicon-pencil"></i> Edit</a>
<a class="btn btn-sm btn-info" ng-click="detailsReminderType(reminderType.ReminderTypeID)"><i class="glyphicon glyphicon-eye-open"></i> View</a>
</td>
<td>{{reminderType.Name}}</td>
<td>{{reminderType.EmailTemplate}}</td>
</tr>
...
<uib-pagination class="pagination-sm"
total-items="totalItems" max-size="maxSize" items-per-page="numPerPage" num-pages="numPages"
ng-model="currentPage" boundary-links="true" rotate="false"></uib-pagination>


and here is the code snippets in controller to do the pagination:

$scope.maxSize = 3;
$scope.totalItems = 7;
$scope.currentPage = 1;
$scope.numPerPage = 2;
$scope.paginate = function (value) {
var begin, end, index;
begin = ($scope.currentPage - 1) * $scope.numPerPage;
end = begin + $scope.numPerPage;
index = $scope.reminderTypes.indexOf(value);
return (begin <= index && index < end);
};


I also check this link on SO, but it doesn't work.
How to make this work to sort and filter the data across the page?

I've posted the complete code in plnkr

Answer

For some reason I'm unable to fork your plunkr, but here is a fix. The JS:

angular.module('ui.bootstrap.demo', ['ngAnimate', 'ui.bootstrap']);
angular.module('ui.bootstrap.demo').controller('PagerDemoCtrl', function($scope) {
  $scope.reminderTypes = [{"ReminderTypeID":1,"Name":"STAMPING OF SPA","EmailTemplate":null},{"ReminderTypeID":2,"Name":"CONDITION PRECEDENT","EmailTemplate":null},{"ReminderTypeID":3,"Name":"STATE AUTHORITY CONSENT","EmailTemplate":null},{"ReminderTypeID":4,"Name":"PAYMENT OF BALANCE PURCHASE PRICE","EmailTemplate":null},{"ReminderTypeID":5,"Name":"CKHT FILING","EmailTemplate":null},{"ReminderTypeID":6,"Name":"TRANSFER FORM 14A","EmailTemplate":null},{"ReminderTypeID":7,"Name":"TRANSFER NOTICE OF ASSESSMENT","EmailTemplate":null}]
  $scope.sortBy = 'Name';
  $scope.sortDescending = false;

  $scope.filteredRT = angular.copy($scope.reminderTypes);

  $scope.searchText = '';

  $scope.maxSize = 3;
  $scope.totalItems = 7;
  $scope.currentPage = 1;
  $scope.numPerPage = 2;
  $scope.paginate = function (value) {
    var begin, end, index;
    begin = ($scope.currentPage - 1) * $scope.numPerPage;
    end = begin + $scope.numPerPage;
    index = $scope.filteredRT.indexOf(value);
    return (begin <= index && index < end);
  };

  $scope.filter = function(){
    var results = $scope.filteredRT;
    results.length = 0;
    var searchText = $scope.searchText;
    var reminderTypes = $scope.reminderTypes;

    for(var i = 0; i < reminderTypes.length; ++i){
      if(searchText.length > 0){
        if(reminderTypes[i].Name.includes(searchText)){
          results.push(reminderTypes[i]);
        }
      } else {
        results.push(reminderTypes[i]);
      }
    }
    $scope.totalItems = results.length;

  }
});

And the HTML

<!doctype html>
<html ng-app="ui.bootstrap.demo">
  <head>
    <script src="//ajax.googleapis.com/ajax/libs/angularjs/1.5.3/angular.js"></script>
    <script src="//ajax.googleapis.com/ajax/libs/angularjs/1.5.3/angular-animate.js"></script>
    <script src="//angular-ui.github.io/bootstrap/ui-bootstrap-tpls-1.3.3.js"></script>
    <script src="example.js"></script>
    <link href="//netdna.bootstrapcdn.com/bootstrap/3.3.6/css/bootstrap.min.css" rel="stylesheet">
  </head>
  <body>

<div ng-controller="PagerDemoCtrl">
  <div class="row">
    <div class="col-md-offset-9 col-md-3">
        <p>
            <div class="input-group">
                <span class="input-group-addon"><i class="glyphicon glyphicon-search"></i></span>
                <input type="text" class="form-control" placeholder="Enter Search Text"
                       ng-model="searchText" ng-change="filter()" />
            </div>
        </p>
    </div>
</div>

<div class="row">
    <div class="col-md-12">
        <table class="table table-striped table-hover table-condensed">
            <thead>
                <tr class="bg-info">
                    <th></th>
                    <th>
                        <a ng-click="sortBy = 'Name'; sortDescending = !sortDescending">Reminder Type Name</a>
                        <span ng-show="sortBy == 'Name' && !sortDescending" class="glyphicon glyphicon-chevron-down"></span>
                        <span ng-show="sortBy == 'Name' && sortDescending" class="glyphicon glyphicon-chevron-up"></span>
                    </th>
                    <th>
                        <a ng-click="sortBy = 'EmailTemplate'; sortDescending = !sortDescending">Email Template</a>
                        <span ng-show="sortBy == 'EmailTemplate' && !sortDescending" class="glyphicon glyphicon-chevron-down"></span>
                        <span ng-show="sortBy == 'EmailTemplate' && sortDescending" class="glyphicon glyphicon-chevron-up"></span>
                    </th>
                </tr>
            </thead>
            <tbody>
                <tr ng-repeat="reminderType in filteredRT | filter: paginate | orderBy:sortBy:sortDescending">
                    <td>
                        <a class="btn btn-sm btn-primary" ng-click="editReminderType(reminderType.ReminderTypeID)"><i class="glyphicon glyphicon-pencil"></i> Edit</a>
                        <a class="btn btn-sm btn-info" ng-click="detailsReminderType(reminderType.ReminderTypeID)"><i class="glyphicon glyphicon-eye-open"></i> View</a>
                    </td>
                    <td>{{reminderType.Name}}</td>
                    <td>{{reminderType.EmailTemplate}}</td>
                </tr>
            </tbody>
            <tfoot>
                <tr>
                    <td colspan="3" class="text-right">
                        Showing page {{currentPage}} of {{numPages}}
                    </td>
                </tr>
            </tfoot>
        </table>
    </div>
</div>

<div class="row">
    <div class="col-md-12 text-center">
        <uib-pagination class="pagination-sm"
                        total-items="totalItems" max-size="maxSize" items-per-page="numPerPage" num-pages="numPages"
                        ng-model="currentPage" boundary-links="true" rotate="false"></uib-pagination>
    </div>
</div>
</div>
  </body>
</html>

In particular, I added a ngChange directive in the input filter, and now a copy of reminderTypes is used. Unfortunately, I think that what you aim to do is a bit too complex to work with angular filters alone. I didn't test the order by but the pagination seems to work just fine in this way.

EDIT : juste adding the correct fork that respond to the question: https://plnkr.co/edit/HMw8U4OUsW5DNDGfQKHY?p=preview