Server-side pagination in AngularJS + ASP.NET MVC
This article talks about how to implement server-side AngularJS pagination in ASP.Net MVC web application.
Introduction
This article is about creating a pagination in an ASP.NET MVC web application using angular-utils-pagination by michaelbromley and PageList by Troy Goode.
i. https://github.com/michaelbromley/angularUtils/tree/master/src/directives/pagination
ii. https://github.com/TroyGoode/PagedList
Background
Basic idea for this pagination method is instead of grabbing data for all the pages, it will only perform ajax to grab the data needed for that specific page each time when user clicks button for next page.
The benefits of server-side pagination approach:
- Much more efficient for large data set (only data set for that page is needed).
- Faster initial load.
- Would not have out of memory issue as browser only stores data set for that specific page.
Using the code
Basic Setup
Create an ASP.Net web application project.
Select MVC
After succesfully created the project, open up Manage NuGet Packages.
Upon Manage NuGet Package screen, search for AngularJS and install.
Next, search for PageList by Troy Goode (https://github.com/TroyGoode/PagedList) in NuGet Package screen and click install.
Then navigate to https://github.com/michaelbromley/angularUtils/tree/master/src/directives/pagination and download the files dirPagination.js and dirPagination.tpl.html.
Alternatively you can install with Bower:
bower install angular-utils-pagination
or npm:
npm install angular-utils-pagination
Now the file set up is completed and we can start coding.
In here we have create a page call "Add Pagination" and will have a list of dishes at the server side.
Server side C#:
For simplicity I'll use hardcoded list as an example, however in actual usage it could be retrieve from a database.
//
// Model to store the list
//
public class DishesModel
{
public List<string> Dishes_List { get; set; }
// Pagination
public int? Page { get; set; }
public int TotalDishesCount { get; set; }
public IPagedList<string> DishesPageList { get; set; }
}
//
// This part could be a web api or in the MVC controller
//
public JsonResult dishesPagination(int? Page)
{
int pageSize = 10;
int pageNumber = (Page ?? 1);
if (Page > 0)
{
dishes_model.Page = Page;
}
List<string> dishes = new List<string>();
DishesModel dishes_model = new DishesModel();
// Hardcoded list for simplicity, it could be from database
for (int i = 1; i < 100; i++)
{
dishes.Add("noodles");
dishes.Add("sausage");
dishes.Add("beans on toast");
dishes.Add("cheeseburger");
dishes.Add("battered mars bar");
dishes.Add("crisp butty");
dishes.Add("yorkshire pudding");
dishes.Add("wiener schnitzel");
dishes.Add("sauerkraut mit ei");
dishes.Add("onion soup");
dishes.Add("bak choi");
dishes.Add("avacado maki");
}
dishes_model.Dishes_List = dishes;
dishes_model.TotalDishesCount = dishes_model.Dishes_List.Count();
dishes_model.DishesPageList = dishes_model.Dishes_List.ToPagedList(pageNumber, pageSize);
return Json(dishes_model);
}
Html:
@{ ViewBag.Title = "Add Pagination"; } <h2>Add Pagination</h2> <div ng-app="myApp" ng-cloak> <div ng-controller="addPaginationCtrl"> <!-- Dishes Table --> <div class="table-responsive table-Item"> <table class="table table-bordered"> <thead> <tr> <th style="text-align:center;" width="10%">#</th> <th>Dish Name</th> </tr> </thead> <tbody> <!-- Loading message --> <tr ng-show="showLoading"> <td colspan="2"> <div><b>{{LoadingText}}</b></div> </td> </tr> <tr dir-paginate="idx in dishesPageList | itemsPerPage:itemsPerPage" total-items="total_count" pagination-id="dishesPagination"> <td>{{itemsPerPage *(pageno-1)+$index+1}}</td> <td>{{idx}}</td> </tr> </tbody> </table> <div align="right"> <dir-pagination-controls max-size="8" direction-links="true" boundary-links="true" pagination-id="dishesPagination" on-page-change="getData(newPageNumber)"> </dir-pagination-controls> </div> </div> </div> </div> <!--angular-utils-pagination library--> <script src="~/Scripts/AngularPagination/dirPagination.js"></script>
Javascript:
<script>
(function ($) {
'use strict';
// Injects "angularUtils.directives.dirPagination" dependency
angular.module("myApp", ["angularUtils.directives.dirPagination"]);
angular.module("myApp").controller("addPaginationCtrl", ["$scope", "addPaginationService", function ($scope, addPaginationService) {
// Initialize variable
$scope.itemsPerPage = 10;
$scope.pageno = 1;
$scope.total_count = 0;
$scope.dishesPageList = [];
// This would fetch the data on page change.
$scope.getData = function (pageno) {
// Proceed to search function once validation success
$scope.LoadingText = "Loading Dishes...";
$scope.showLoading = true;
// Resets page list and total count on each page change
$scope.dishesPageList = [];
$scope.total_count = 0;
// Assign new page number
$scope.pageno = pageno;
addPaginationService.searchDishesPage(pageno)
.then(function (result) {
// if total dish count more than zero hides the loading text
if (result.TotalDishesCount > 0) {
$scope.showLoading = false;
}
else {
$scope.LoadingText = "Dishes not available.";
$scope.showLoading = true;
};
// Assigns total count and page list
$scope.total_count = result.TotalDishesCount;
$scope.dishesPageList = result.DishesPageList;
}, function () {
// error
$scope.LoadingText = "Error occur, please try again.";
$scope.showLoading = true;
}).finally(function () {
// called no matter success or failure
});
};
// Initial load set to page 1
$scope.getData(1);
}]);
angular.module("myApp").factory("addPaginationService", ["$http", function ($http) {
var service = {};
var dishesList = [];
service.getDishesList = function () {
return dishesList;
};
// Ajax call to server to retrieve dishes data based on page number
service.searchDishesPage = function (pageno) {
var model = {
Page: pageno
}
return $http({
method: "POST",
url: '@Url.Action("dishesPagination", "Home")',
headers: { 'Content-Type': 'application/json; charset=utf-8' },
data: model
}).then(
function successCallback(response) {
dishesList = response.data.DishesPageList;
return response.data;
},
function errorCallback(response) {
console.log("Search Dishes Error:" + response);
// May add exception code
});
};
return service;
}]);
})(jQuery);
</script>
Testing the App
Compiled and execute the web application.
Demo web site: http://mytutorial.yolio.my.tmp13.mschosting.com/home/addpagination
Points of Interest
To learn how to implement ASP.Net MVC pagination in AngularJS.
History
- 13th August, 2016: First version