We had exactly the same requirement what you have described. We searched on web we didn't get the solution. Finally we researched and came up with a solution. Hope it will help others who are looking for solution.
We are using Angular ui grid. In angular ui.grid you can either use default client side pagination or you can implement external(or server side) pagination.
But, In your requirement, you need combination of client and server side pagination, which is flexible and very much required when you have huge data (number of records in Lacks).
If you don't know how to use server side pagination then look at How to use Angular UI-Grid with Server Side Paging question. You can have a look at working server side pagination implementation http://plnkr.co/edit/UttxPkXG8fYQDX85fnyZ?p=preview.
I am modifying this implementation in order to achieve combination of client side and server side pagination.
var useHybridPagination = true;
var paginationPageSize = 25;
var serverPaginationPageSize = 2500;
var serverPaginationOffset = 0;
var serverPaginationGridData = {};
var clientPaginationOptions = {
pageNumber: 1,
pageSize: paginationPageSize,
};
var serverPaginationOptions = {
pageNumber: 1,
pageSize: serverPaginationPageSize,
};
var paginationRowRange = {}
paginationRowRange.startRowIndex = 1;
paginationRowRange.endRowIndex = paginationPageSize;
var serverPaginationRowRange = {}
serverPaginationRowRange.startRowIndex = 1;
serverPaginationRowRange.endRowIndex = serverPaginationPageSize;
I am going to use Server side pagination logic to pull every 2,500 records. And to navigate across pages at client side (2500 records), will going to make little modification. if the new page sought by user exists in 2500 records at client side then slice the number of records as indicated by serverPaginationOptions.pageSize and load the grid. Or else fetch next 2500 records & re-evaluate row indexes.
$scope.clientPaginationOptions = clientPaginationOptions ;
$scope.serverPaginationOptions = serverPaginationOptions;
$scope.paginationRowRange = paginationRowRange;
$scope.serverPaginationRowRange = serverPaginationRowRange;
$scope.serverPaginationOffset = serverPaginationOffset;
$scope.serverPaginationGridData = serverPaginationGridData;
$scope.gridOptions = {
paginationPageSizes: [25, 50, 75],
paginationPageSize: $scope.clientPaginationOptions .pageSize,
useExternalPagination: true,
columnDefs: [
{ name: 'name' },
{ name: 'gender', enableSorting: false },
{ name: 'company', enableSorting: false }
],
onRegisterApi: function(gridApi) {
$scope.gridApi = gridApi;
gridApi.pagination.on.paginationChanged($scope, function (newPage, pageSize) {
$scope.clientPaginationOptions .pageNumber = newPage;
$scope.clientPaginationOptions .pageSize = pageSize;
let startRowIndex = (($scope.clientPaginationOptions .pageNumber - 1) * $scope.clientPaginationOptions .pageSize) + 1;
let endRowIndex = (startRowIndex - 1 ) + clientPaginationOptions .pageSize;
if(endRowIndex > $scope.serverPaginationRowRange.endRowIndex || startRowIndex < $scope.serverPaginationRowRange.startRowIndex){
$scope.serverPaginationOptions.pageNumber = parseInt(($scope.clientPaginationOptions .pageNumber * pageSize)/$scope.serverPaginationOptions.pageSize) + 1;
let serverStartRowIndex = (($scope.serverPaginationOptions.pageNumber - 1) * $scope.serverPaginationOptions.pageSize) + 1;
let serverEndRowIndex = (serverStartRowIndex - 1 ) + $scope.serverPaginationOptions.pageSize;
let paginationRowRangeTmp = {}
paginationRowRangeTmp.startRowIndex = serverStartRowIndex;
paginationRowRangeTmp.endRowIndex = serverEndRowIndex;
$scope.serverPaginationRowRange = paginationRowRangeTmp;
$scope.serverPaginationOffset = serverStartRowIndex - 1;
}
startRowIndex = startRowIndex - $scope.serverPaginationOffset;
endRowIndex = endRowIndex - $scope.serverPaginationOffset;
let paginationRowRangeTmp = {}
paginationRowRangeTmp.startRowIndex = startRowIndex;
paginationRowRangeTmp.endRowIndex = endRowIndex;
$scope.paginationRowRange = paginationRowRangeTmp;
getPage();
});
}
};
getPage();
var getPage = function() {
if(useHybridPagination && !_.isEmpty($scope.serverPaginationGridData)){
var currentPageData = getcurrentPageData();
$timeout(function() {
$scope.gridOptions.data = datatoLoadGrid;
}, 1);
}
else{
var url = 'https://cdn.rawgit.com/angular-ui/ui-grid.info/gh-pages/data/100.json';
$http.get(url,$scope.serverPaginationRowRange)
.then(function (returnData) {
$scope.gridOptions.totalItems = returnData.data.totalPaginationRecords;
let datatoLoadGrid = returnData.data.gridData;
if(useHybridPagination){
$scope.serverPaginationGridData = datatoLoadGrid;
datatoLoadGrid = getcurrentPageData();
}
$scope.gridOptions.data = datatoLoadGrid;
});
}
};
var getcurrentPageData = function(){
var gridData = [];
var tmpGridrecords = $scope.serverPaginationGridData;
if(!_.isEmpty(tmpGridrecords) && tmpGridrecords.length > 0)
gridData = tmpGridrecords.slice($scope.paginationRowRange.startRowIndex-1, $scope.gridOptions.endRowIndex);
return gridData;
};
As you can see, the web service (or API) returns data object with 2 properties - totalPaginationRecords & gridData. totalPaginationRecords is total number of records possible i.e. in our case it is 20,000. gridData is the grid data to be loaded (Page size 2500).
All corner conditions are handled. Hope it helps. All suggestions/corrections to improve this solution are welcome.