AngularJS is an excellent framework, and ng-grid is great for quickly getting rich table functionality. However, the one part of ng-grid I have really struggled to understand due to a lack of any documentation is the expected behaviour for ng-grid pagination. I can read the code and example provided on the ng-grid Getting Started site. But I cannot understand whether the fact that it doesn't work correctly is my own user error, or whether the ng-grid behaviour is broken with the version of angular I am using.
Starting with Versions, I am on Angular 1.2.17, angular-grid (ng-grid) 2.0.11, and have Jquery 2.1 (which is ahead of the default dependency version ng-grid uses).
Question 1: Is the pagination really Server side or Client side? In other words, is the API call expected to bring down every result set row from the server, and then subsequently paginate on that in the UI, or can it truly do server side pagination with say query params limit=x&offset=y.
Question 2: If ng-grid does not pull down the entire resultset up front - How does ng-grid know what the total number of items are when the pagination works with a discrete limit and offset?
Here is my UI code below which works fine, the $scope.getPagedDataAsync gets invoked, goes to the server and pulls down just the limit and offset defined.
Suppose I have 50 records on server. I ask for limit=10&offset=10 - that would give me records 11-20 from server etc.
$scope.getPagedDataAsync = function (pageSize, page, searchText) {
setTimeout(function () {
var data, limit = pageSize, offset = ((page * pageSize) - pageSize);
if (searchText) {
var ft = searchText.toLowerCase();
DfmAdminAgency.query(function (largeLoad) {
data = largeLoad.filter(function (item) {
return JSON.stringify(item).toLowerCase().indexOf(ft) !== -1;
});
$scope.setPagingData(data, page, pageSize);
});
} else {
DfmAdminAgency.query({limit: pageSize, offset: offset}, function (largeLoad) {
$scope.setPagingData(largeLoad, page, pageSize);
});
}
}, 100);
};
The pagesize option is not working properly whether I introduce limit and offset or not. It is ok if starting with say pagesize 50 and then decreasing it. But if I then go back from say pagesize 10 to pagesize 50 it fails to update the table contents with the extra rows.
Really, just some simple explanation of what the expected behaviour is would be much appreciated. That way I can actually report what is not doing as expected.
I probably should re-iterate, I do believe I can read the code well enough for the getting started example. It appears that:
$scope.totalServerItems
is what controls what ng-grid believes is the total server items. And this gets set to the size of the data passed into method "setPagingData":
$scope.totalServerItems = data.length;
But in method "getPagedDataAsync" in order to et the value of "data":
DfmAdminAgency.query(function (largeLoad) {
$scope.setPagingData(largeLoad, page, pageSize);
});
The above gets called when paging between pages on ng-grid. In other words, it is making a query to the server for the full result set EVERY time the pagination is clicked... which would indicate really, it is grabbing the entire result set from the server, and then just doing quasi-local pagination. Surely that isn't intended behaviour?! Or is it the responsibility of the data service provider to retain the information on full data size, and cache data etc to provide to the ng-grid table were recalling the server for the same data would be inappropriate?
As I see the example on the ng-grid documentation it is merely intended to simulate a server call. The grid does work with serverside paging but it is up to the server to respond appropriately which I assume you have handled. You have not included your setPagingData method but if it is similar to the docs you have probably gotten a mix of serverside and clientside paging.
We have a getData method like this (omitting error handling):
function getData() {
$resource(urlService.getBaseUrl() + $scope.restUrl + ':id').query({
page: $scope.pagingOptions.currentPage,
pageSize: $scope.pagingOptions.pageSize
}, function (responseItems, getResponseHeaders) {
var xPageObject = getResponseHeaders('x-pagination');
xPageObject = angular.fromJson(xPageObject);
if (xPageObject) {
$scope.totalPages = xPageObject.TotalPages;
$scope.totalItems = xPageObject.TotalCount;
} else {
console.log("No paging header found");
}
$scope.items = responseItems;
});
}
our server method then pages appropriately. To ensure we update when paging options changes add a watch on the pagingoptions:
// Listen on changes to currentPage and reload when updated
$scope.$watch('pagingOptions', function (newVal, oldVal) {
if (newVal !== oldVal) {
if (newVal.pageSize !== oldVal.pageSize) {
newVal.currentPage = 1;
}
getData();
}
}, true);
This will ensure that whatever change is made to paging it will result in a new request.
With regards to your totalServerItems question it is defined in the options which scope variable the grid will use:
$scope.options = {
columnDefs: 'columnDefinitions',
data: 'items',
totalServerItems: 'totalItems'
};
In my case the $scope.totalItems contains the total number of items and it gets populate in the success callback from the response header.
HTH
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With