Click here to Skip to main content
65,938 articles
CodeProject is changing. Read more.
Articles / AngularJs

AngularJS + ASP.NET Web API: Building a Simple Grid in AngularJS with Server-side Paging, Sorting, Searching (Part 3)

5.00/5 (6 votes)
26 Feb 2015CPOL2 min read 14.5K  
In the previous post, I populated the grid with data returned from an API, and in today's post I'll incorporate paging.

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:

NgWebApiGrid19

Paste this markup below the closing </table> tag in the students.tpl.html file as given below:

HTML
<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:

JavaScript
.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.

JavaScript
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:

NgWebApiGrid20

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:

C#
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:

JavaScript
.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.

JavaScript
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:

JavaScript
.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:

HTML
<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:

NgWebApiGrid21

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.


License

This article, along with any associated source code and files, is licensed under The Code Project Open License (CPOL)