Custom Paging With Angular

Introduction
 
This example explains about the custom paging in an HTML grid with AngularJS. The paging also works with Search filter. Going into further detail, we will create a grid which has search filter and other filters where paging will also be working. We will create directive for paging so that the same code will be used many times as we want.
 
Download the requred JavaScript and CSS files from the below links.
Gettiing Started
  • Open Visual Studio and create a new MVC web application.
  • Copy the downloaded AngularJS file in "Scripts" folder of the solution.
  • Create a JavaScript file and name it as Module.js.
  • Then, write the following code in it.  
  1. var app = angular.module("myApp",[]);  
  • Module.js file registers the application with myApp key.
  • This key is used with ng-app tag like ng-app="myApp".
  • Create another file Controller.js.
  • We register controller.js with app keyword.
  1. app.controller("gridController"function($scope, $rootScope) {    
  2.   
  3. });    
  • The Controller key gridController is used on HTML page like ng-controller="gridController" on body tag or on div tag inside the body tag. This will allow us to access all the functions inside the controller.js file on that HTML page.
    • After that, let's create another JavaScript file Service.js for calling the server methods.
    • We register service.js again with app keyword.      
    1. app.service("Service"function ($http) {  
    2.   
    3. });     
    The Service key Service is used in controller.js file, like
    1. app.controller("gridController"function ($scope, Service) {  
    2.   
    3. })  
    This will allow us to access all the functions inside the service.js file on Controller file. From service.js file, we can make call to server and send the results back to Controller.

    Start writing the code in Controller.js file.     

    1. app.controller("gridController"function($scope, $rootScope) {    
    2.             var data = [];    
    3.             var columns = [];    
    4.           
    5.             columns.push({    
    6.                 "key""Component",    
    7.                 "width""9%",    
    8.                 "dataType""string",    
    9.                 "showTags""false",    
    10.                 "showColumns""true"    
    11.             });    
    12.             columns.push({    
    13.                 "key""Class Code",    
    14.                 "width""3%",    
    15.                 "dataType""string",    
    16.                 "showTags""false",    
    17.                 "showColumns""true"    
    18.             });    
    19.             columns.push({    
    20.                 "key""Caption",    
    21.                 "width""13%",    
    22.                 "dataType""string",    
    23.                 "showTags""false",    
    24.                 "showColumns""true"    
    25.             });    
    26.             columns.push({    
    27.                 "key""Dept",    
    28.                 "width""1%",    
    29.                 "dataType""string",    
    30.                 "showTags""false",    
    31.                 "showColumns""true"    
    32.             });    
    33.             columns.push({    
    34.                 "key""Rank",    
    35.                 "width""1%",    
    36.                 "dataType""string",    
    37.                 "showTags""false",    
    38.                 "showColumns""true"    
    39.             });    
    40.             columns.push({    
    41.                 "key""Interval",    
    42.                 "width""3%",    
    43.                 "dataType""string",    
    44.                 "showTags""false",    
    45.                 "showColumns""true"    
    46.             });    
    47.             columns.push({    
    48.                 "key""Start Date",    
    49.                 "width""4%",    
    50.                 "dataType""date",    
    51.                 "showTags""false",    
    52.                 "showColumns""false"    
    53.             });    
    54.             columns.push({    
    55.                 "key""End Date",    
    56.                 "width""4%",    
    57.                 "dataType""date",    
    58.                 "showTags""false",    
    59.                 "showColumns""false"    
    60.             });    
    61.             columns.push({    
    62.                 "key""Date/ Hours",    
    63.                 "width""3%",    
    64.                 "dataType""date",    
    65.                 "showTags""false",    
    66.                 "showColumns""true"    
    67.             });    
    68.             columns.push({    
    69.                 "key""Action",    
    70.                 "width""4%",    
    71.                 "dataType""commands",    
    72.                 "showTags""false",    
    73.                 "showColumns""true"    
    74.             });    
    75.             $rootScope.columns = eval(columns);   
    This code is used to create columns. We store column array into scope.      
    1. data.push({    
    2.     "Component""Me Cyl. Head [6]",    
    3.     "Class Code""MDECYA",    
    4.     "Caption""OVH, TST, CLN OF Me Cyl. Head [6]",    
    5.     "Dept""ENG",    
    6.     "Rank""2E",    
    7.     "ID""00006",    
    8.     "Interval""6000 R/Hs",    
    9.     "Date/ Hours""6129 R/Hs",    
    10.     "Action"""    
    11. });    
    12. data.push({         
    13.     "Component""Me Injector Valves W/Pipes [3]",    
    14.     "Class Code""MDECYA",    
    15.     "Caption""TST, INSP OF Me Injector Valves W/Pipes [3]",    
    16.     "Dept""ENG",    
    17.     "Rank""CE",    
    18.     "ID""00011",    
    19.     "Interval""500 R/Hs",    
    20.     "Date/ Hours""2812 R/Hs",    
    21.     "Action"""    
    22. });    
    23. data.push({        
    24.     "Component""Me Fo Pre-Heater",    
    25.     "Class Code""",    
    26.     "Caption""TST, CLN, INSP OF Me Fo Pre-Heater",    
    27.     "Dept""ENG",    
    28.     "Rank""2E",    
    29.     "ID""00150",    
    30.     "Interval""30 M",    
    31.     "Date/ Hours""5/20/2017",    
    32.     "Action"""    
    33. });    
    34. data.push({    
    35.     "Component""Me Flowmeter",    
    36.     "Class Code""",    
    37.     "Caption""INSP, CLN OF Me Flowmeter",    
    38.     "Dept""ENG",    
    39.     "Rank""2E",    
    40.     "ID""00151",    
    41.     "Interval""30 M",    
    42.     "Date/ Hours""5/19/2017",    
    43.     "Action"""    
    44. });    
    45. data.push({    
    46.     "Component""Ae Cyl. Head [1] [3]",    
    47.     "Class Code""MDECYA",    
    48.     "Caption""OVH, INSP OF Ae Cyl. Head [1] [3]",    
    49.     "Dept""ENG",    
    50.     "Rank""3E",    
    51.     "ID""00164",    
    52.     "Interval""1500 R/Hs",    
    53.     "Date/ Hours""3845 R/Hs",    
    54.     "Action"""    
    55. });    
    56. data.push({    
    57.     "Component""D/E Frequency Low [1]",    
    58.     "Class Code""",    
    59.     "Caption""TST, INSP OF D/E Frequency Low [1]",    
    60.     "Dept""ENG",    
    61.     "Rank""ETO",    
    62.     "ID""00922",    
    63.     "Interval""6 M",    
    64.     "Date/ Hours""11/14/2016",    
    65.     "Action"""    
    66. });    
    67. data.push({    
    68.     "Component""Boiler Fo Booster Pump Stbd",    
    69.     "Class Code""",    
    70.     "Caption""OVH, INSP OF Boiler Fo Booster Pump Stbd",    
    71.     "Dept""ENG",    
    72.     "Rank""2E",    
    73.     "ID""00470",    
    74.     "Interval""30 M",    
    75.     "Date/ Hours""5/6/2017",    
    76.     "Action"""    
    77. });    
    78. data.push({    
    79.     "Component""Boiler Safety Valve",    
    80.     "Class Code""",    
    81.     "Caption""OVH, INSP OF Boiler Safety Valve",    
    82.     "Dept""ENG",    
    83.     "Rank""3E",    
    84.     "ID""00473",    
    85.     "Interval""12 M",    
    86.     "Date/ Hours""9/23/2016",    
    87.     "Action"""    
    88. });    
    89. data.push({    
    90.     "Component""Air Condition Condenser",    
    91.     "Class Code""",    
    92.     "Caption""TST, INSP OF Air Condition Condenser",    
    93.     "Dept""ENG",    
    94.     "Rank""2E",    
    95.     "ID""00554",    
    96.     "Interval""30 M",    
    97.     "Date/ Hours""6/1/2017",    
    98.     "Action"""    
    99. });    
    100. data.push({    
    101.     "Component""Sludge Pump",    
    102.     "Class Code""",    
    103.     "Caption""OVH, INSP OF Sludge Pump",    
    104.     "Dept""ENG",    
    105.     "Rank""2E",    
    106.     "ID""00588",    
    107.     "Interval""30 M",    
    108.     "Date/ Hours""5/22/2017",    
    109.     "Action"""    
    110. });    
    111. data.push({    
    112.     "Component""Bilge Filters",    
    113.     "Class Code""",    
    114.     "Caption""CLN, INSP OF Bilge Filters",    
    115.     "Dept""ENG",    
    116.     "Rank""2E",    
    117.     "ID""00589",    
    118.     "Interval""1 M",    
    119.     "Date/ Hours""9/5/2016",    
    120.     "Action"""    
    121. });    
    122. data.push({    
    123.     "Component""Emergency Bilge Suction - Er",    
    124.     "Class Code""",    
    125.     "Caption""TST, INSP OF Emergency Bilge Suction - Er",    
    126.     "Dept""ENG",    
    127.     "Rank""2E",    
    128.     "ID""00591",    
    129.     "Interval""1 M",    
    130.     "Date/ Hours""9/5/2016",    
    131.     "Action"""    
    132. });    
    133. data.push({    
    134.     "Component""Hydraulic For Operating Valve System",    
    135.     "Class Code""",    
    136.     "Caption""ANL, INSP OF Hydraulic For Operating Valve System",    
    137.     "Dept""ENG",    
    138.     "Rank""2E",    
    139.     "ID""00594",    
    140.     "Interval""6 M",    
    141.     "Date/ Hours""12/2/2016",    
    142.     "Action"""    
    143. });    
    144. $rootScope.gridData = eval(data);  
    This code is used to show static data into grid. I am using static data but you can get the data from server and        show in the grid.

    For that, follow the steps given in another article - Click Here. 
    Create new JavaScript file for Paging directive.
    Give name PageFilter.js to this JavaScript file.
    This directive is used through out the project for paging.
    1. app.filter('pagination'function () {      
    2.     return function (input, start) {  
    3.         start = parseInt(start, 10);  
    4.         return input.slice(start);  
    5.     }  
    6. }); 
    After that, write the following code in Angular Controller for paging.
    1. $scope.range = function () {  
    2.         var rangeSize = 4;  
    3.         var ps = [];  
    4.         var start;  
    5.         start = $scope.currentPage;  
    6.         if (start > $scope.pageCount() - rangeSize) {  
    7.             start = $scope.pageCount() - rangeSize + 1;  
    8.         }  
    9.         for (var i = start; i < start + rangeSize; i++) {  
    10.   
    11.             if (i != -1 && i != -2 && i != -3 && i != -4) {  
    12.                 ps.push(i);  
    13.             }  
    14.         }  
    15.         return ps;  
    16.     };  
    17.   
    18.     $scope.prevPage = function () {  
    19.         if ($scope.currentPage > 0) {  
    20.             $scope.currentPage--;  
    21.         }  
    22.     };  
    23.   
    24.     $scope.DisablePrevPage = function () {  
    25.         return $scope.currentPage === 0 ? "disabled" : "";  
    26.     };  
    27.   
    28.     $scope.pageCount = function () {  
    29.         return Math.ceil($scope.filtered.length / $scope.itemsPerPage) - 1;  
    30.     };  
    31.   
    32.     $scope.nextPage = function () {  
    33.         if ($scope.currentPage < $scope.pageCount()) {  
    34.             $scope.currentPage++;  
    35.         }  
    36.     };  
    37.   
    38.     $scope.DisableNextPage = function () {  
    39.         if ($scope.pageCount() < 0) {  
    40.             return $scope.currentPage === 0 ? "disabled" : "";  
    41.         }  
    42.         else {  
    43.             return $scope.currentPage === $scope.pageCount() ? "disabled" : "";  
    44.         }  
    45.     };  
    46.   
    47.     $scope.setPage = function (n) {  
    48.         $scope.currentPage = n;  
    49.     };  
    In this code, methods are written to calulate the number of pages according to total count of records. For next page click, for previous page click, and disable the next and previous page according to the current page.

    Now, create an MVC View from Controller and start writing the following code in that.
    1. @{    
    2.     ViewBag.Title = "Home Page";    
    3. }    
    4.     
    5. <html ng-app="myapp">    
    6. <head>    
    7.     <title></title>    
    8.     
    9.     <style>    
    10.            .paginationclass {    
    11.             margin: 15px 28px;    
    12.         }    
    13.     
    14.             .paginationclass div {    
    15.                 border-bottom: 1px solid silver;    
    16.             }    
    17.     
    18.             .paginationclass span {    
    19.                 margin: 0px 15px;    
    20.                 display: inline-block;    
    21.                 padding: 5px 0px;    
    22.                 text-align: left;    
    23.                 width: 70px;    
    24.             }    
    25.     
    26.         .pagination-controle li {    
    27.             display: inline-block;    
    28.         }    
    29.     
    30.         .pagination-controle button {    
    31.             width: 63px;    
    32.             font-size: 12px;    
    33.             margin-left: 13px;    
    34.             cursor: pointer;    
    35.         }    
    36.     
    37.         .pagination-div {    
    38.             margin-left: 20px;    
    39.         }    
    40.     
    41.         .nodatatxt {    
    42.             opacity: 0.25;    
    43.             font-size: 1.5em;    
    44.             width: 100%;    
    45.             text-align: center;    
    46.             z-index: 1000;    
    47.         }    
    48.     </style>    
    49. </head>    
    50. <body>    
    51.     <div class="container" ng-controller="Controller">   
    52. <input type="text" placeholder="Search" ng-model="search" class="form-control"/>
    53.   <table cellpadding="12" class="table table-bordered table-hover table-striped">    
    54.          <tr>    
    55.                 <th ng-repeat="(header,val) in EcoList"></th>    
    56.         </tr>    
    57.     
    58.  <tr data-ng-repeat="(key,val) in gridData |filter:search |pagination : currentPage*itemsPerPage | limitTo: itemsPerPage ">    
    59.                 <td ng-repeat="column in columns">    
    60.                     {{val[column.key]}}    
    61.                 </td>    
    62.             </tr></table>
    63.         <div class="form-group">                
    64.             <div class="pagination-div">    
    65.                 <ul class="pagination">    
    66.                     <li ng-class="DisablePrevPage()">    
    67.                         <a href ng-click="prevPage()">« Prev</a>    
    68.                     </li>    
    69.                     <li ng-repeat="n in range()"    
    70.                         ng-class="{active: n == currentPage}"    
    71.                         ng-click="setPage(n)">    
    72.                         <a href="#">{{n+1}}</a>    
    73.                     </li>    
    74.                     <li ng-class="DisableNextPage()">    
    75.                         <a href ng-click="nextPage()">Next »</a>    
    76.                     </li>    
    77.                 </ul>    
    78.             </div>    
    79.         </div>    
    80.     </div>    
    81.     
    82. </body>    
    83. </html>   
    On View page, we just use ng-repeat on $scope.gridData and $scope.columns to generate columns and fill data with just writing one line of code.

    And div and anchor tags are used for page buttons.

    Include all the JavaScript files including the page filter file in bundle and call the bundle on layout page or use all the JS files directly on the cshtml page.