AngularJS - Sort, Filter and Paging - A Table Directive

AngularJS is GREAT!
you should neglect whatever framework you are using right now,
and switch to AngularJS immediately!

In the following posts I will show you how you can easily
write a reusable table with sorting, filter and paging!
And it is all reusable, customizable and easy - thanks to AngularJS! You guys rock!
At the end I will show you how it all comes together,
and I will provide a github link to the source code.
This example is great for advanced programming in AngularJS.
For production purposes you should definitely check out AngularUI's NG-Grid project.
Outcome
Weeks after writing these posts (not all published yet) - I came across a nice project called "smart table" - what do you know?
After you read my posts, you will know how to write this "smart table" plugin in AngularJS.
Let me use this opportunity to point out this plugin did a nice job with the filtering feature.
It simply placed an input field on every column header - which is very intuitive and space is used well.
More Possible Features

What I show in these posts is the basics.
You can easily modify them to include server side filtering,
customizable templates, page jump links and probably a lot more.
Getting Started
Before we begin implementing the features, we need to set the environment.
For data, I decided to use a nifty cool tool for JSON data generation. However, since they will not save my JSON for longer than 30 days,
I saved their output into a google doc, and I serve it from my google drive.

Below you can find an HTML template to start from.
This template shows a simple AngularJS usage for building a table from JSON data.
I added some basic CSS to comfort.
For some reason, using $http.get did not go that well, so I used JQuery instead.
<html ng-app="myApp">
 <head>
  <style>
   body {background-color:#cecece; margin:0; padding:0; font-family:Arial; }
   body>div:first-child {width:50%; margin:auto; margin-top:40px;}
   table {border:none; border-collapse:collapse; width:100%;}
   table tr { border:none;}
   table tr td { border:none; font-size:37px; font-weight:bolder;}
   table tr:first-child{background-color:#00ff00;}
   table tr:nth-child(2n){ background-color:blue;}
   table tr:nth-child(2n+3){ background-color:red;}
  </style>
  <script src="http://ajax.googleapis.com/ajax/libs/jquery/2.0.0/jquery.min.js"></script>
  <script src="http://code.angularjs.org/1.0.6/angular.min.js"></script>

  <script type="text/javascript">
 
   var myApp = angular.module("myApp",[]);

   myApp.controller("PostController", function( $scope, $http ){
    $scope.headers = ["name","age"];
    $scope.availableHeaders = [];
    // using JQuery because $http does not work as expected here..
    $.ajax({
     url:"https://googledrive.com/host/0BzBTj4P1uKcAMVVNa0VySm5fbjg",
     success:function(d){
      $scope.$apply(function(){
       $scope.data = JSON.parse(d)["result"];
       for ( header in $scope.data ){
        $scope.availableHeaders.push(header);
       }
       console.log($scope.data)
      });    
    }
    });
   });
  </script>
 </head>
 <body ng-controller="PostController">
  <div>
   <table>
    <tr>
     <td ng-repeat="head in headers">
      {{head}}
     </td>
       </tr>
       <tr ng-repeat="d in data">
        <td ng-repeat="head in headers">
         {{d[head]}}
        </td>
       </tr>
   </table>
  </div>
 </body>
</html>
The complete code
Here is the code as it should look like at the end.

<html ng-app="myApp">
  <head>
<style>
body {background-color:#cecece; margin:0; padding:0; font-family:Arial; }
body>div:first-child {width:50%; margin:auto; margin-top:40px;}
table {border:none; border-collapse:collapse; width:100%;}
table tr { border:none;}
table tr td { border:none; font-size:37px; font-weight:bolder;}
table tr:first-child{background-color:#00ff00;}
table tr:nth-child(2n){ background-color:blue;}
table tr:nth-child(2n+3){ background-color:red;}
table tr:first-child td.sortBy:after{
display:block;
content:"";
height:0;
width:0;
border:10px solid transparent;
}
table tr:first-child td.desc:after{
border-color: black transparent transparent transparent;
}

table tr:first-child td.asc:after{
border-color: transparent transparent black transparent;
}

</style>
<script src="http://ajax.googleapis.com/ajax/libs/jquery/2.0.0/jquery.min.js"></script>
<script src="http://code.angularjs.org/1.0.6/angular.min.js"></script>

<script type="text/javascript">

var myApp = angular.module("myApp",[]);

myApp.controller("PostController", function( $scope, $http ){
$scope.headers = ["name","age"];
$scope.dataPageSize = 30;
$scope.setPageSize = function(pageSize){$scope.dataPageSize = pageSize;}
$scope.toggleHeader = function( header ){
var headerIndex = $scope.headers.indexOf(header);
if (  headerIndex >= 0 ){
$scope.headers.splice(headerIndex,1);
}else{
$scope.headers.push(header);
}
};

$scope.orderTableBy = function(header){
                    if ( $scope.orderHeader == header && $scope.orderDirection == false){
                        $scope.orderHeader = null; // clear sort.
                    }
                    else if ( $scope.orderHeader == header ){
                        $scope.orderDirection = false;
                    }else{
                      $scope.orderHeader = header;
                        $scope.orderDirection = true;
                    }
                };

$scope.availableHeaders = [];
// using JQuery because $http does not work as expected here..
$.ajax({
url:"https://googledrive.com/host/0BzBTj4P1uKcAMVVNa0VySm5fbjg",
success:function(d){
$scope.$apply(function(){
$scope.data = JSON.parse(d)["result"];
for ( header in $scope.data[0] ){
$scope.availableHeaders.push(header);
}
console.log($scope.data)
});
}
});
});

myApp.filter("pagingFilter", function(){
return function(input, currentPage, pageSize ){
return input ?  input.slice(currentPage * pageSize, currentPage * ( pageSize + 1 )) : [];
}

});
myApp.directive("paging", function(){

        return {
            template:'<div><button ng-disabled="!hasPrevious()" ng-click="onPrev()"> Previous </button> {{start()}} - {{end()}} out of {{size()}} <button ng-disabled="!hasNext()" ng-click="onNext()"> Next </button><div ng-transclude=""></div> </div>',
            restrict:'AEC',
            transclude:true,
            scope:{
                'currentPage':'=',
                'pageSize':'=',
                'data':'&'

            },
            link:function($scope, element, attrs){

                $scope.size = function(){

                    return angular.isDefined($scope.data()) ? $scope.data().length : 0;
                };

                $scope.end = function(){
                    return $scope.start() + $scope.pageSize;
                };

                $scope.start = function(){
                    return $scope.currentPage * $scope.pageSize;
                };

                $scope.page = function(){
                    return !!$scope.size() ? ( $scope.currentPage + 1 ) : 0;
                };

                $scope.hasNext = function(){
                    return $scope.page() < ( $scope.size() /  $scope.pageSize )  ;
                };

                $scope.onNext = function(){
                    $scope.currentPage = parseInt($scope.currentPage) + 1;
                };

                $scope.hasPrevious = function(){
                    return !!$scope.currentPage;
                } ;

                $scope.onPrev = function(){
                    $scope.currentPage=$scope.currentPage-1;
                };

                try{
                    if ( typeof($scope.data) == "undefined"){
                        $scope.data = [];
                    }
                    if ( typeof($scope.currentPage) == "undefined" ){
                        $scope.currentPage = 0;
                    }
                    if ( typeof($scope.pageSize) == "undefined"){
                        $scope.pageSize = 10;
                    }
                }catch(e){ console.log(e);}
            }

        }

})


</script>
</head>
<body ng-controller="PostController">
<div>
<div class="search-bar">
        <label>Search</label><input ng-model="searchText">
    </div>
<div class="available-headers">
<span class="available-header" ng-click="toggleHeader(header)" ng-repeat="header in availableHeaders" style="border:1px solid black; padding:10px; border-radius:10px; line-height:40px;">
{{header}}
</span>
</div>
<div class="page-size" style="padding-top:10px; padding-bottom:10px;">
page size :
<a href="javascript:void(0)" style="padding-left:10px" ng-click="setPageSize(pageSize)" ng-repeat="pageSize in [10,20,30]"> {{pageSize}}</a>
</div>
<paging data="tableData = ( data | orderBy:orderHeader:orderDirection | filter:searchText  )" current-page="dataCurrentPage" page-size="dataPageSize">
<table>
<tr>
<td
ng-class="{
'sortBy' : head == orderHeader,
'asc':head == orderHeader && orderDirection == true,
'desc':head == orderHeader && orderDirection == false
}"
ng-click="orderTableBy(head)"
ng-repeat="head in headers">
{{head}}
</td>
    </tr>
    <tr ng-repeat="d in tableData  | pagingFilter:dataPageSize:dataCurrentPage">
    <td ng-repeat="head in headers">
    {{d[head]}}
    </td>
    </tr>
</table>
Found {{tableData.length}} search results
  </paging>
</div>
</body>
</html>

7 comments

Angularjs training is essential for developing any single page web application. You have to learn Angularjs indepth to creating enterpirse SPA application.

Angularjs Training | Angular.js Course | Angularjs Online Training | Angularjs Training in Chennai | AngularJS Interview Questions

Reply

Hi Bro,

Hip Hip Hooray! I was always told that slightly slow in the head, a slow learner. Not anymore! It’s like you have my back. I can’t tell you how much I’ve learnt here and how easily! Thank you for blessing me with this effortlessly ingestible digestible content.

I have a question,
In Angular 2, How can we get the user name of the logged in user.

I log in to the windows computer with the network credentials. So how can i get the user name in angular application. If we can directly get user name in angular2. what is the application solution to implement using angular2.

Super likes !!! for this amazing post. I thinks everyone should bookmark this.

Many Thanks,

Reply

Thank you for sharing this useful blog. It will help to improve my career. Also, it is a wonderful blog for everyone.
AngularJS Training in Chennai | AngularJS Course in Chennai | AngularJS Training Institute in Chennai | Angular 2 Training in Chennai

Reply

It is an extremely useful blog for learning AngularJS. Much obliged to you for sharing this brilliant blog.
Angular 4 Training in Chennai | AngularJS Training Chennai | AngularJS Courses in Chennai | Angular Training in Chennai

Reply

very informative blog and useful article thank you for sharing with us , keep posting AngularJS Online Training |AngularJS Online Training Hyderabad

Reply

This is really an awesome article. Thank you for sharing this.It is worth reading for everyone.
Offshore Angularjs Developers in India

Reply

Post a Comment