In the previous post, I populated the grid with data returned from an API, and in today’s post I’ll incorporate paging.
Head over to http://angular-ui.github.io/bootstrap/ & from the directives dropdown, select “pagination”
You should see a set of pagination controls – each styled a bit differently, feel free to take a look at the markup and JavaScript & play with them in plunker to get familiar with how they work.
I like the one that limits the maximum number of visible buttons – so go ahead and copy the markup, I’ve highlighted the markup we’ll be copying below:
Paste this markup below the closing </table>
tag in the students.tpl.html file as given below:
<div class="row top-buffer">
<table class="table table-bordered table-striped table-responsive">
<thead>
<tr>
<th>
</th>
<th>
</th>
<th>
</th>
<th>
Last Name
</th>
<th>
First Name
</th>
<th>
Date of Enrollment
</th>
</tr>
</thead>
<tbody data-ng-repeat="i in data">
<tr>
<td></td>
<td></td>
<td></td>
<td>
<textarea class="form-control" style="width: 300px;height: 65px"
ng-model="i.lastName"></textarea>
</td>
<td>
<textarea class="form-control" style="width: 300px;height: 65px"
ng-model="i.firstMidName"></textarea>
</td>
<td>
<input type="text" class="form-control"
style="width: 150px;height: 65px" ng-model="i.enrollmentDate" />
</td>
</tr>
</tbody>
</table>
<pagination data-total-items="totalItems" ng-model="currentPage"
data-max-size="NumberOfPageButtons" class=" pagination-sm"
data-boundary-links="true" data-rotate="false"
ng-change="pageChanged()" data-items-per-page="recordsPerPage"></pagination>
</div>
In the student.js file, the studentCtrl
should look like this:
.controller("studentCtrl", ["$scope", "dataService",
function($scope, dataService) {
$scope.data = dataService.students;
$scope.totalItems = 0;
$scope.currentPage = 1;
$scope.maxSize = 5;
$scope.recordsPerPage = 5;
$scope.NumberOfPageButtons = 5;
getData($scope, dataService);
$scope.pageChanged = function() {
console.log('Page changed to: ' + $scope.currentPage);
};
}]);
Also, make sure the ui.bootstrap
dependency is getting injected when the ngWebApiGrid.student
module is created, if you forget to inject this dependency then pagination component will not show and no error will be thrown when you inspect your console.
angular.module('ngWebApiGrid.student', ['ngRoute', 'ui.bootstrap'])
.config(["$routeProvider", function($routeProvider) {
$routeProvider.when("/", {
controller: "studentCtrl",
templateUrl: "app/simpleGrid/students.tpl.html"
});
$routeProvider.otherwise("/");
}])
Run the solution, you should now see a pagination directive displayed as follows:
If you click on any of the buttons in the pagination control, nothing happens, that’s because we still have to wire-up our controller and data service to fetch the data – let’s do that next.
Go to the StudentsApiController
and it should look like this:
public StudentsContainer GetStudents(int currentPage, int recordsPerPage)
{
var pageNumber = currentPage;
var pageSize = recordsPerPage;
var begin = (pageNumber - 1) * pageSize;
var totalNumberOfRecords = db.Students.Count();
var students = db.Students.OrderBy(r=>r.ID).Skip(begin).Take(pageSize).ToList();
var studentsContainer = new StudentsContainer
{ Students = students, RecordCount = totalNumberOfRecords };
return studentsContainer;
}
The code above should be self explanatory; essentially, we grab the page number and page size and calculate the records to be returned.
Now go over to the student.js file and modify the dataService
to pass the currentPage
and pageSize
while making the Get
request to the StudentsApiController
above:
.factory("dataService", ["$http", "$q", function($http, $q) {
var _students = [];
var deferred = $q.defer();
var _getStudents = function(options) {
$http.get("api/StudentsApi?currentPage=" + options.currentPage +
"&" + "recordsPerPage=" + options.recordsPerPage)
.then(function(result) {
angular.copy(result.data.students, _students);
deferred.resolve(result.data.recordCount);
},
function() {
deferred.reject();
});
return deferred.promise;
};
return {
students: _students,
getStudents: _getStudents,
};
}])
Next, let’s create a helper function called getData()
. This function will be called by our controller when it has to fetch the data.
var getData = function ($scope, dataService) {
var options = {
};
options.currentPage = $scope.currentPage;
options.recordsPerPage = $scope.recordsPerPage;
dataService.getStudents(options)
.then(function (totalItems) {
$scope.totalItems = totalItems;
},
function () {
alert("error occurred: unable to get data");
});
};
Lastly, modify the controller to make the call to the getData()
function. The getData()
function will get called when the page first loads and then each time the user clicks on the pagination buttons.
The controller code should look like below:
.controller("studentCtrl", ["$scope", "dataService",
function($scope, dataService) {
$scope.data = dataService.students;
$scope.totalItems = 0;
$scope.currentPage = 1;
$scope.maxSize = 5;
$scope.recordsPerPage = 5;
$scope.NumberOfPageButtons = 5;
getData($scope, dataService);
$scope.pageChanged = function() {
getData($scope, dataService);
};
}]);
The pagination control in the students.tpl.html should look as follows:
<pagination data-total-items="totalItems" ng-model="currentPage"
data-max-size="NumberOfPageButtons" class=" pagination-sm" data-boundary-links="true"
data-rotate="false" ng-change="pageChanged()"
data-items-per-page="recordsPerPage"></pagination>
You should now be able to page through the data:
The source code is available at https://github.com/SangeetAgarwal/NgWebApiGrid and you can see the changes I made for this blog post by looking at this commit.
You might have noticed that there is a lag between the page first appearing and data getting loaded into the grid – this is especially noticeable over a slow network connection or when you are paging through the data very quickly – next time, we’ll incorporate a loading/progress bar to let the user know that things are happening.