Use Angular UI Grid With Server Side Pagination In ASP.NET MVC Application

Introduction

Angular UI Grid is a data grid for AngularJS without JQuery that can perform with large data, which is part of the Angular UI suite.

Background

Recently, I was searching for a data table that have components like sorting, filtering, pagination, inline editor, responsive and other advanced facilities. I have tried to integrate & use Jquery datatable(Angular), but the problem arose while I was trying to pass entire row passing while row click/row selected button click.

It fails to pass angular object (only can pass int, string, boolean) while rendering, this was a big issue to me as I was using angularJS in the application's frontend.

I decided to change the entire table, I found Angular UI Grid.

Let’s Get Into It

As we know Angular UI Grid is a part of Angular UI, so we have some facilities. We need to download/install package before we are going to use in our application.

To download the package, go to URL,

grid

SQL Database

Let’s Create a SQL database, using the new database execute the table script to create new table in the new database.

  1. CREATE TABLE [dbo].[tblProducts](  
  2. [ProductID] [intNOT NULL,  
  3. [ProductTitle] [nvarchar](256) NULL,  
  4. [Type] [nvarchar](50) NULL,  
  5. [Price] [numeric](18, 2) NULL,  
  6. [CreatedOn] [datetime] NULL,  
  7. CONSTRAINT [PK_tblProducts] PRIMARY KEY CLUSTERED   
  8. (  
  9. [ProductID] ASC  
  10. )WITH (PAD_INDEX = OFF, STATISTICS_NORECOMPUTE = OFF, IGNORE_DUP_KEY = OFF, ALLOW_ROW_LOCKS = ON, ALLOW_PAGE_LOCKS = ONON [PRIMARY]  
  11. ON [PRIMARY]  
  12.   
  13. GO  
Demo Data
  1. INSERT INTO [tblProducts]  
  2. SELECT 1,'Ape Lifestyle Cotton Casual T-Shirt - Gray','Clothing',270.00,getdate()  
  3. Union All  
  4. SELECT 2,'Cotton Casual Short Sleeve Polo - White','Clothing',790.50,getdate()  
  5. Union All  
  6. SELECT 3,'Cotton Casual Shirt - Sky Blue and White Stripe','Clothing',1555.00,getdate()  
  7. Union All  
  8. SELECT 4,'Cotton Mix Casual Panjabi - Thistle and Gray Stripe','Clothing',2458.00,getdate()  
  9. Union All  
  10. SELECT 5,'Cotton Mix Casual Panjabi - Black and Purple Stripe','Clothing',2458.00,getdate()  
  11. Union All  
  12. SELECT 6,'Cotton Casual Shirt - Red and White Check','Clothing',1735.00,getdate()  
  13. Union All  
  14. SELECT 7,'Kingstar TITANS 1 i19 Smartphone 8GB - White','Smartphone',6300.00,getdate()  
  15. Union All  
  16. SELECT 8,'MyCell Spider A4 Smartphone 8GB – White','Smartphone',7770.00,getdate()  
  17. Union All  
  18. SELECT 9,'HTC One M9S Nano-SIM Smartphone 16GB - Silver','Smartphone',26900.00,getdate()  
  19. Union All  
  20. SELECT 10,'WE X1 Smartphone 16GB – Silver','Smartphone',18600.00,getdate()  
  21. Union All  
  22. SELECT 11,'Microsoft Lumia 540 Smartphone 8GB – Cyan','Smartphone',13999.00,getdate()  
  23. Union All  
  24. SELECT 12,'BlackBerry Z10 Smartphone 16GB - White','Smartphone',18000.00,getdate()  
  25. Union All  
  26. SELECT 13,'Ape Lifestyle Cotton Casual T-Shirt - Gray','Clothing',270.00,getdate()  
  27. Union All  
  28. SELECT 14,'Cotton Casual Short Sleeve Polo - White','Clothing',790.50,getdate()  
  29. Union All  
  30. SELECT 15,'Cotton Casual Shirt - Sky Blue and White Stripe','Clothing',1555.00,getdate()  
  31. Union All  
  32. SELECT 16,'Cotton Mix Casual Panjabi - Thistle and Gray Stripe','Clothing',2458.00,getdate()  
  33. Union All  
  34. SELECT 17,'Cotton Mix Casual Panjabi - Black and Purple Stripe','Clothing',2458.00,getdate()  
  35. Union All  
  36. SELECT 18,'Cotton Casual Shirt - Red and White Check','Clothing',1735.00,getdate()  
  37. Union All  
  38. SELECT 19,'Kingstar TITANS 1 i19 Smartphone 8GB - White','Smartphone',6300.00,getdate()  
  39. Union All  
  40. SELECT 20,'MyCell Spider A4 Smartphone 8GB – White','Smartphone',7770.00,getdate()  
  41. Union All  
  42. SELECT 21,'HTC One M9S Nano-SIM Smartphone 16GB - Silver','Smartphone',26900.00,getdate()  
  43. Union All  
  44. SELECT 22,'WE X1 Smartphone 16GB – Silver','Smartphone',18600.00,getdate()  
  45. Union All  
  46. SELECT 23,'Microsoft Lumia 540 Smartphone 8GB – Cyan','Smartphone',13999.00,getdate()  
  47. Union All  
  48. SELECT 24,'BlackBerry Z10 Smartphone 16GB - White','Smartphone',18000.00,getdate()  
MVC Application

Let’s create a new demo application with visual studio 2015. Select MVC and Web API below. Click OK.

app

After loading the initial application template, we need to install the script packages. We need to install two packages using NuGet Package installer.

First we will install AngularJS and after that we need to add Angular-Ui-Grid. In package manager console write Install-Package angularjs. After successfully installation write Install-Package angular-ui-grid.

code

Or we can install packages using NuGet package manager,

angularJS

angularJS

angularJS-uigrid

angularJS

Our packages are installed, now we need to add a new controller and generate view to the application. In our master layout we need to add reference of script library.

library

In the head section add the ui style reference.

reference

AngularJS

Let’s add folders to create angular script.

create

JS-Module
  1. var app;  
  2. (function () {  
  3. 'use strict';  
  4. app = angular.module('UIGrid_App',  
  5. [  
  6. 'ngAnimate'// support for CSS-based animations  
  7. 'ngTouch'//for touch-enabled devices  
  8. 'ui.grid'//data grid for AngularJS  
  9. 'ui.grid.pagination'//data grid Pagination  
  10. 'ui.grid.resizeColumns'//data grid Resize column  
  11. 'ui.grid.moveColumns'//data grid Move column  
  12. 'ui.grid.pinning'//data grid Pin column Left/Right  
  13. 'ui.grid.selection'//data grid Select Rows  
  14. 'ui.grid.autoResize'//data grid Enabled auto column Size  
  15. 'ui.grid.exporter' //data grid Export Data  
  16. ]);  
  17. })();  
JS-Controller
  1. app.controller('ProductsCtrl', ['$scope''CRUDService''uiGridConstants',  
  2. function ($scope, CRUDService, uiGridConstants) {  
  3. $scope.gridOptions = [];  
  4.   
  5. //Pagination  
  6. $scope.pagination = {  
  7. paginationPageSizes: [15, 25, 50, 75, 100, "All"],  
  8. ddlpageSize: 15,  
  9. pageNumber: 1,  
  10. pageSize: 15,  
  11. totalItems: 0,  
  12.   
  13. getTotalPages: function () {  
  14. return Math.ceil(this.totalItems / this.pageSize);  
  15. },  
  16. pageSizeChange: function () {  
  17. if (this.ddlpageSize == "All")  
  18. this.pageSize = $scope.pagination.totalItems;  
  19. else  
  20. this.pageSize = this.ddlpageSize  
  21.   
  22. this.pageNumber = 1  
  23. $scope.GetProducts();  
  24. },  
  25. firstPage: function () {  
  26. if (this.pageNumber > 1) {  
  27. this.pageNumber = 1  
  28. $scope.GetProducts();  
  29. }  
  30. },  
  31. nextPage: function () {  
  32. if (this.pageNumber < this.getTotalPages()) {  
  33. this.pageNumber++;  
  34. $scope.GetProducts();  
  35. }  
  36. },  
  37. previousPage: function () {  
  38. if (this.pageNumber > 1) {  
  39. this.pageNumber--;  
  40. $scope.GetProducts();  
  41. }  
  42. },  
  43. lastPage: function () {  
  44. if (this.pageNumber >= 1) {  
  45. this.pageNumber = this.getTotalPages();  
  46. $scope.GetProducts();  
  47. }  
  48. }  
  49. };  
  50.   
  51. //ui-Grid Call  
  52. $scope.GetProducts = function () {  
  53. $scope.loaderMore = true;  
  54. $scope.lblMessage = 'loading please wait....!';  
  55. $scope.result = "color-green";  
  56.   
  57. $scope.highlightFilteredHeader = function (row, rowRenderIndex, col, colRenderIndex) {  
  58. if (col.filters[0].term) {  
  59. return 'header-filtered';  
  60. else {  
  61. return '';  
  62. }  
  63. };  
  64. $scope.gridOptions = {  
  65. useExternalPagination: true,  
  66. useExternalSorting: true,  
  67. enableFiltering: true,  
  68. enableSorting: true,  
  69. enableRowSelection: true,  
  70. enableSelectAll: true,  
  71. enableGridMenu: true,  
  72.   
  73. columnDefs: [  
  74. { name: "ProductID", displayName: "Product ID", width: '10%', headerCellClass: $scope.highlightFilteredHeader },  
  75. { name: "ProductTitle", title: "Product Title", width: '40%', headerCellClass: $scope.highlightFilteredHeader },  
  76. { name: "Type", title: "Type", headerCellClass: $scope.highlightFilteredHeader },  
  77. {  
  78. name: "Price", title: "Price", cellFilter: 'number',  
  79. filters: [{ condition: uiGridConstants.filter.GREATER_THAN, placeholder: 'Minimum' }, { condition: uiGridConstants.filter.LESS_THAN, placeholder: 'Maximum' }],  
  80. headerCellClass: $scope.highlightFilteredHeader  
  81. },  
  82. { name: "CreatedOn", displayName: "Created On", cellFilter: 'date:"short"', headerCellClass: $scope.highlightFilteredHeader },  
  83. {  
  84. name: 'Edit',  
  85. enableFiltering: false,  
  86. enableSorting: false,  
  87. width: '5%',  
  88. enableColumnResizing: false,  
  89. cellTemplate: '<span class="label label-warning label-mini">' +  
  90. '<a href="" style="color:white" title="Select" ng-click="grid.appScope.GetByID(row.entity)">' +  
  91. '<i class="fa fa-check-square" aria-hidden="true"></i>' +  
  92. '</a>' +  
  93. '</span>'  
  94. }  
  95. ],  
  96. exporterAllDataFn: function () {  
  97. return getPage(1, $scope.gridOptions.totalItems, paginationOptions.sort)  
  98. .then(function () {  
  99. $scope.gridOptions.useExternalPagination = false;  
  100. $scope.gridOptions.useExternalSorting = false;  
  101. getPage = null;  
  102. });  
  103. },  
  104. };  
  105.   
  106. var NextPage = (($scope.pagination.pageNumber - 1) * $scope.pagination.pageSize);  
  107. var NextPageSize = $scope.pagination.pageSize;  
  108. var apiRoute = 'api/Product/GetProducts/' + NextPage + '/' + NextPageSize;  
  109. var result = CRUDService.getProducts(apiRoute);  
  110. result.then(  
  111. function (response) {  
  112. $scope.pagination.totalItems = response.data.recordsTotal;  
  113. $scope.gridOptions.data = response.data.productList;  
  114. $scope.loaderMore = false;  
  115. },  
  116. function (error) {  
  117. console.log("Error: " + error);  
  118. });  
  119. }  
  120.   
  121. //Default Load  
  122. $scope.GetProducts();  
  123.   
  124. //Selected Call  
  125. $scope.GetByID = function (model) {  
  126. $scope.SelectedRow = model;  
  127. };  
  128. }  
  129. ]);  
  130. JS-Service  
  131. app.service('CRUDService', function ($http) {  
  132. //**********----Get Record----***************  
  133. this.getProducts = function (apiRoute) {  
  134. return $http.get(apiRoute);  
  135. }  
  136. });  
Ui-Grid

In index.cshtml page add ui-grid directive

directive

The loader which will show a loading messaging while data is loading from server.

server

At bottom end, add angular reference to the page

reference

Complete Ui Code
  1. @{  
  2. ViewBag.Title = "Products";  
  3. }  
  4.   
  5. <h3>Products with UI Grid</h3>  
  6.   
  7. <div class="row">  
  8. <div class="col-md-12" ng-controller="ProductsCtrl">  
  9. <div ui-grid="gridOptions"  
  10. ui-grid-resize-columns  
  11. ui-grid-move-columns  
  12. ui-grid-exporter  
  13. ui-grid-selection  
  14. ui-grid-pinning class="grid"></div>  
  15.   
  16. <div class="loadmore">  
  17. <div ng-show="loaderMore" ng-class="result">  
  18. <img src="~/Content/ng-loader.gif" />  
  19. {{lblMessage}}  
  20. </div>  
  21. </div>  
  22.   
  23. <div role="contentinfo" class="ui-grid-pager-panel ng-scope">  
  24. <div role="navigation" class="ui-grid-pager-container">  
  25. <div role="menubar" class="ui-grid-pager-control">  
  26. <!-- Start Page -->  
  27. <button type="button" role="menuitem" class="ui-grid-pager-first" ui-grid-one-bind-title="aria.pageToFirst"  
  28. ui-grid-one-bind-aria-label="aria.pageToFirst"  
  29. ng-click="pagination.firstPage()"  
  30. ng-disabled="cantPageBackward()" title="Page to first" aria-label="Page to first"  
  31. disabled="disabled">  
  32. <div class="first-triangle">  
  33. <div class="first-bar"></div>  
  34. </div>  
  35. </button>  
  36.   
  37. <!-- Prev Page -->  
  38. <button type="button" role="menuitem" class="ui-grid-pager-previous"  
  39. ui-grid-one-bind-title="aria.pageBack" ui-grid-one-bind-aria-label="aria.pageBack"  
  40. ng-click="pagination.previousPage()"  
  41. ng-disabled="cantPageBackward()" title="Page back" aria-label="Page back" disabled="disabled">  
  42. <div class="first-triangle prev-triangle"></div>  
  43. </button>  
  44.   
  45. <input type="number" ui-grid-one-bind-title="aria.pageSelected" ui-grid-one-bind-aria-label="aria.pageSelected"  
  46. class="ui-grid-pager-control-input ng-pristine ng-untouched ng-valid ng-not-empty ng-valid-min ng-valid-max ng-valid-required"  
  47. ng-model="pagination.pageNumber"  
  48. min="1" max="{{pagination.getTotalPages()}}" required="" title="Selected page"  
  49. aria-label="Selected page" disabled>  
  50.   
  51. <span class="ui-grid-pager-max-pages-number ng-binding"  
  52. ng-show="pagination.getTotalPages() > 0">  
  53. <abbr ui-grid-one-bind-title="paginationOf" title="of"> /</abbr>{{pagination.getTotalPages()}}  
  54. </span>  
  55.   
  56. <!-- Next Page -->  
  57. <button type="button" role="menuitem" class="ui-grid-pager-next" ui-grid-one-bind-title="aria.pageForward"  
  58. ui-grid-one-bind-aria-label="aria.pageForward"  
  59. ng-click="pagination.nextPage()"  
  60. ng-disabled="cantPageForward()"  
  61. title="Page forward" aria-label="Page forward">  
  62. <div class="last-triangle next-triangle"></div>  
  63. </button>  
  64.   
  65. <!-- Last Page -->  
  66. <button type="button" role="menuitem" class="ui-grid-pager-last"  
  67. ui-grid-one-bind-title="aria.pageToLast" ui-grid-one-bind-aria-label="aria.pageToLast"  
  68. ng-click="pagination.lastPage()" ng-disabled="cantPageToLast()" title="Page to last" aria-label="Page to last">  
  69. <div class="last-triangle"><div class="last-bar"></div></div>  
  70. </button>  
  71. </div><!-- ngIf: grid.options.paginationPageSizes.length > 1 -->  
  72.   
  73. <div class="ui-grid-pager-row-count-picker ng-scope" @*ng-if="pagination.ddlpageSize.length > 1"*@>  
  74. <select ng-model="pagination.ddlpageSize"  
  75. ng-options="o as o for o in pagination.paginationPageSizes" ng-change="pagination.pageSizeChange()"  
  76. class="ng-pristine ng-untouched ng-valid ng-not-empty"></select>  
  77. <span class="ui-grid-pager-row-count-label ng-binding"> items per page</span>  
  78. </div>  
  79. <!-- end ngIf: grid.options.paginationPageSizes.length > 1 -->  
  80. <!-- ngIf: grid.options.paginationPageSizes.length <= 1 -->  
  81. </div>  
  82. <div class="ui-grid-pager-count-container">  
  83. <div class="ui-grid-pager-count">  
  84. <span ng-show="pagination.totalItems > 0" class="ng-binding">  
  85. {{pagination.pageNumber}}<abbr ui-grid-one-bind-title="paginationThrough" title="through"> - </abbr>{{pagination.ddlpageSize}} of {{pagination.totalItems}} items  
  86. </span>  
  87. </div>  
  88. </div>  
  89. </div>  
  90.   
  91. <p>{{SelectedRow}}</p>  
  92. </div>  
  93. </div>  
  94. @section AngularScript{  
  95. <script src="~/ScriptsNg/Controllers/ProductsCtrl.js"></script>  
  96. <script src="~/ScriptsNg/Service/CRUDService.js"></script>  
  97. }  
Model - Our Ui is ready Let’s create a new model in our demo application.

application

I have used api controller to get data from server, which will get called while pagination operates.

Api-Controller
  1. [RoutePrefix("api/Product")]  
  2. public class ProductController : ApiController  
  3. {  
  4. private dbUIGrid_Entities _ctx = null;  
  5.   
  6. [HttpGet, ResponseType(typeof(tblProduct)), Route("GetProducts/{pageNumber:int}/{pageSize:int}")]  
  7. public IHttpActionResult GetProducts(int pageNumber, int pageSize)  
  8. {  
  9. List<tblProduct> productList = nullint recordsTotal = 0;  
  10. try  
  11. {  
  12. using (_ctx = new dbUIGrid_Entities())  
  13. {  
  14. recordsTotal = _ctx.tblProducts.Count();  
  15. productList = _ctx.tblProducts.OrderBy(x => x.ProductID)  
  16. .Skip(pageNumber)  
  17. .Take(pageSize)  
  18. .ToList();  
  19. }  
  20. }  
  21. catch (Exception)  
  22. {  
  23. }  
  24. return Json(new  
  25. {  
  26. recordsTotal,  
  27. productList  
  28. });  
  29. }  
  30. }  
Final Output:

Output

Filter Data

Output

Hope this will help.