michaelbromley / angularUtils

A place where I will collect useful re-usable Angular components that I make
MIT License
2k stars 858 forks source link

Pagination: pageChanged handler should accept `newPageSize` when working with Asynchronous Data #212

Open benoror opened 9 years ago

benoror commented 9 years ago

When working with Asynchronous Data, a change in pageSize should re-trigger an async call as well (and possibly do some recalculation):

$scope.pageChanged = function(newPage, newPageSize) {
    getResultsPage(newPage, newPageSize);
};
<dir-pagination-controls on-page-change="pageChanged(newPageNumber, newPageSize)"></dir-pagination-controls>
benoror commented 9 years ago

Looking at uigrid's code I found a clue for the way the watcher is written:

https://github.com/angular-ui/ui-grid/blob/7420b4b54eba5798053b99d1c6c0dcc67c530080/src/features/pagination/js/pagination.js#L377

benoror commented 9 years ago

Ok this is how I implemented this on application level, aklthoug it would be nice to be incorporated into the directive:

View:

<div class="panel-footer clearfix">
  <div class="pull-left">
    <select
      ng-model="vm.options.paginationPageSize"
      ng-options="o as o for o in vm.options.paginationPageSizes">
    </select>
    records per page
  </div>
  <dir-pagination-controls
    boundary-links="true"
    template-url="directives/shared/dirPagination.tpl.html">
  </dir-pagination-controls>
</div>

Controller:

  var vm = this;

  // Default options
  vm.options = {};
  vm.options.paginationPageSizes = [4, 8, 16, 32, 64, 128];
  vm.options.totalItems = 100;
  vm.options.paginationPageSize = 10;
  vm.options.currentPage = 1;

  // Instead of using on-page-change attribute, implement this watcher:
  $scope.$watch('vm.options.currentPage + vm.options.paginationPageSize', (newValues, oldValues) => {
    if (newValues === oldValues) {
      return;
    }
    vm.makeAjaxCall(vm.options.currentPage, vm.options.paginationPageSize)
  });
benoror commented 9 years ago

Updated to avoid infinite loops in some scenarios:

  var vm = this;

  // Default options
  vm.options = {};
  vm.options.paginationPageSizes = [4, 8, 16, 32, 64, 128];
  vm.options.totalItems = 100;
  vm.options.paginationPageSize = 10;
  vm.options.currentPage = 1;

  vm.getTotalPages = function() {
    if (!vm.catalog.totalItems) { // (!vm.options.enablePagination) {
      return null;
    }
    return (vm.options.totalItems === 0) ? 1 : Math.ceil(vm.options.totalItems / vm.options.paginationPageSize);
  };

  // Instead of using on-page-change attribute, implement this watcher:
  $scope.$watch('vm.options.currentPage + vm.options.paginationPageSize', (newValues, oldValues) => {
    if (newValues === oldValues || oldValues === undefined) {
      return;
    }
    if (!angular.isNumber(vm.options.currentPage) || vm.options.currentPage < 1) {
      vm.options.currentPage = 1;
      return;
    }
    if (vm.options.totalItems > 0 && vm.options.currentPage > vm.getTotalPages()) {
      vm.options.currentPage = vm.getTotalPages();
      return;
    }

    vm.paginationChangeHandler({
      newPage: vm.options.currentPage,
      newPageSize: vm.options.paginationPageSize
    });
  });

Actually full credit goes to @brianchance who implemented this feature in ui-grid back in Nov 2014.