Tutorial: Basic DataTable (sorting, filtering and pagination) with AngularJS and ng-Table

In this tutorial I’m going to show you how to create a simple DataTable with some basic features, which are sorting, filtering and pagination. To accomplish this I’m going to use AngularJS with the module ng-Table.

First we need to create our project, after doing it, no matter your folder structure, you should have a html file to host your table (I’m going to use index.html) and also a js file to put your angular code (app.js).

Initially they should look like this:

Index.html

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
<!DOCTYPE html>
<html ng-app="ngTableTutorial">
    <head>
        <title>TODO supply a title</title>
        <meta charset="UTF-8">
        <meta name="viewport" content="width=device-width, initial-scale=1.0">
        <script src="http://cdnjs.cloudflare.com/ajax/libs/angular.js/1.4.2/angular.js"></script>
        <link href="http://netdna.bootstrapcdn.com/bootstrap/3.3.1/css/bootstrap.min.css" rel="stylesheet" media="screen">
        <script src="http://netdna.bootstrapcdn.com/bootstrap/3.3.1/js/bootstrap.min.js" type="text/javascript"></script>
        <link rel="stylesheet" href="https://rawgit.com/esvit/ng-table/master/dist/ng-table.min.css">
        <script src="https://rawgit.com/esvit/ng-table/master/dist/ng-table.min.js"></script>
        <link href="app/resources/css/style.css" rel="stylesheet" type="text/css"/>
        <script src="app/resources/js/app.js" type="text/javascript"></script>
    </head>
    <body>
        <div ng-controller="tableController">
 
        </div>
    </body>
</html>

app.js

1
2
3
4
5
angular.module('ngTableTutorial', ['ngTable'])
        .controller('tableController', function ($scope, $filter, ngTableParams) {
 
            });
        });

I’ve already referenced all the js and css files we’re going to use, and as you can see, I have also defined the angular module and controller. This is our initial project structure, if you run it, since we didn’t added anything yet, you’ll just see a blank page on your browser.

Now let’s get started with our table, the first thing we need is some data display on it, since we’re not using a database for this tutorial, a static JSON will do the job (You can use the website mockaroo to generate some data to test your app). After you get the data you can store it in a variable on your controller, your code should look like this:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
angular.module('ngTableTutorial', ['ngTable'])
        .controller('tableController', function ($scope, $filter, ngTableParams) {
 
            $scope.users = [{"id":1,"first_name":"Philip","last_name":"Kim","email":"pkim0@mediafire.com","country":"Indonesia","ip_address":"29.107.35.8"},
                        {"id":2,"first_name":"Judith","last_name":"Austin","email":"jaustin1@mapquest.com","country":"China","ip_address":"173.65.94.30"},
                        {"id":3,"first_name":"Julie","last_name":"Wells","email":"jwells2@illinois.edu","country":"Finland","ip_address":"9.100.80.145"},
                        {"id":4,"first_name":"Gloria","last_name":"Greene","email":"ggreene3@blogs.com","country":"Indonesia","ip_address":"69.115.85.157"},
                        .
                        .
                        .
                        {"id":50,"first_name":"Andrea","last_name":"Greene","email":"agreene4@fda.gov","country":"Russia","ip_address":"128.72.13.52"}];
 
            });
        });

With the data available we can now start creating our table on the index.html, the first feature we’re going to implement will be the pagination, although it’s getting old, I’m going to use it anyway for this tutorial, but I strongly recommend you to create a table with infinite scroll, I’ll show you how to do that in another tutorial.

To create the table just put the following code inside your div tag:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
<table ng-table="usersTable" class="table table-striped">
   <tr ng-repeat="user in data">
       <td data-title="'Id'" >
           {{user.id}}
       </td>
       <td data-title="'First Name'" >
           {{user.first_name}}
       </td>
       <td data-title="'Last Name'" >
           {{user.last_name}}
       </td>    
       <td data-title="'e-mail'" >
           {{user.email}}
       </td>    
       <td data-title="'Country'">
           {{user.country}}
       </td>    
       <td data-title="'IP'" >
           {{user.ip_address}}
       </td>    
   </tr>
</table>

This is the table structure with all the available columns of our JSON, if your data has different columns you just have to change their names in the td tag. An important thing to note is that I didn’t use our users variable in the ng-repeat, later I will explain why.

Also note that I’ve already defined the ng-table attribute in the table tag, now we have to declare it on the app.js, copy this code and put it below the $scope.users declaration:

1
2
3
4
5
6
7
8
9
10
$scope.usersTable = new ngTableParams({
                page: 1,
                count: 10
            }, {
                total: $scope.users.length, 
                getData: function ($defer, params) {
                    $scope.data = $scope.users.slice((params.page() - 1) * params.count(), params.page() * params.count());
                    $defer.resolve($scope.data);
                }
            });

All I’m doing is defining the page size and also the initial page, this is done by the ‘count’ and ‘page’ attributes respectively. But the most important thing here is the getData function, it will be called every time you refresh our table, in other words, every time you filter, paginate or sort our data. Since our only feature is pagination for now, the getData function will only be responsible to get from the $scope.users the data displayed on our current page, I’ve used the splice function for that and stored the results in my auxiliary variable $scope.data (I couldn’t use the $scope.users because it would override my initial data).

If you run your project this will be the result:

ng-TableWithPagination
ng-Table with pagination

Now let’s add the sort functionality to the table, in your index.html just add the attribute sortable to the columns. Here is one example:

1
2
3
<td data-title="'Id'" sortable="'id'">
    {{user.id}}
</td>

You also need to change a little bit the getData function:

1
2
3
4
5
getData: function ($defer, params) {
   $scope.data = params.sorting() ? $filter('orderBy')($scope.users, params.orderBy()) : $scope.users;
   $scope.data = $scope.data.slice((params.page() - 1) * params.count(), params.page() * params.count());
   $defer.resolve($scope.data);
}

I just added the first line which is responsible for sorting the data before slicing and returning it.

The last feature we’re going to add is the filter, as we did for the sorting functionality we’re just going to add one more attribute to the columns, the ‘filter’:

1
2
3
<td data-title="'First Name'" sortable="'first_name'" filter="{ 'first_name': 'text' }">
  {{user.first_name}}
</td>

For enable filtering we also have to put the attribute show-filter on the table:

1
<table ng-table="usersTable" show-filter=”true” class="table table-striped">

And lastly, add one more line to the getData function, which will be responsible for filtering our data:

1
2
3
4
5
6
getData: function ($defer, params) {
   $scope.data = params.sorting() ? $filter('orderBy')($scope.users, params.orderBy()) : $scope.users;
   $scope.data = params.filter() ? $filter('filter')($scope.data, params.filter()) : $scope.data;
   $scope.data = $scope.data.slice((params.page() - 1) * params.count(), params.page() * params.count());
   $defer.resolve($scope.data);
}

if you run your project you’ll see the final result:

ng-Table with sort, filter and pagination features
ng-Table with sort, filter and pagination features

That’s it, now we have our datatable with sorting, filtering and pagination.
Hope this tutorial was helpful for you.
Till next time!

Related Posts:
Tutorial: Implementing Infinite Scroll with AngularJS and ngInfiniteScroll
Tutorial: Creating Reusable Code with AngularJS Directives

38 comments on “Tutorial: Basic DataTable (sorting, filtering and pagination) with AngularJS and ng-Table

  1. powolnymarcel

    If you have a problem make sure that this line is correct :
    it’s for the filtering

    $scope.data = $scope.data.slice((params.page() - 1) * params.count(), params.page() * params.count());
    1. Leonardo Jines

      In this case it should be slice(), I just want to get a subset of items from the array without modifying it, the splice() function would remove the elements from the array.

  2. tabish

    after filtering the result, even if a single row is available, pagination part still exist with same no of pages with unfiltered result.

  3. amenzoweb

    Hello , thank you for your nice tutorial

    i have a question when i replaced your data by a ( GET http) i got data but my table is empty in page loading it show data only when i click in any sort or filter some words.

    do you have idea of that please?

    Thank you so much

  4. Marcel

    How would such an example be if the user data was from an api service.
    I did like:

    $scope.users = null;
     
    $http.get('http://myapplication.dev/api')
        .success(function(data){
            $scope.users = data;
    });

    and the url gives me back:

    [{"id":1,"gender":"Female","first_name":"Janet","last_name":"Bell","email":"jbell0@gizmodo.com","ip_address":"164.132.30.212"}, 
    {"id":2,"gender":"Male","first_name":"Andrew","last_name":"Meyer","email":"ameyer1@blinklist.com","ip_address":"180.32.94.134"}, 
    {"id":3,"gender":"Male","first_name":"Carl","last_name":"Allen","email":"callen2@homestead.com","ip_address":"255.172.14.98"}, 
    {"id":4,"gender":"Female","first_name":"Donna","last_name":"Matthews","email":"dmatthews3@oaic.gov.au","ip_address":"234.46.125.231"}, 
    {"id":5,"gender":"Male","first_name":"Todd","last_name":"Harper","email":"tharper4@163.com","ip_address":"100.93.245.15"}, 
    {"id":125,"gender":"Male","first_name":"George","last_name":"Williamson","email":"gwilliamson3g@mail.ru","ip_address":"5.228.123.22"}]

    But the page stays all white…

    I also read about the previous comment, but how can we slow down the page load, while in the mean time I want a fast responsive application?

    can you give us some hints based on your experience?

    1. Leonardo Jines

      There’s nothing wrong with your code, but if your problem is the same mentioned in the previous comment try using $scope.$apply.

  5. Arpit

    Great Tutorial , Many Thanks Leonardo

    The Only Issue when we use filter it still shows the same pagination . It should be change as the result change according to the filters value.

    Please share how can we make pagination according to filter results.

  6. liang

    hello Leonardo. Thank you for your example here. I don’t have much experience in angularjs. If I want to get the users data from my controller instead of putting all data in app.js, how would you do that?

    1. Leonardo Jines

      I’m not sure if I understand your question, the controller is in the app.js file, and the data is already coming from it.

      1. liang

        I want to pull the data from the my rails controller.
        my app/controllers/stocks_controller.rb:

        class StocksController < ApplicationController
           def index
              @stocks = Stock.all
              render json: @stocks
          end
        end

        my angularjs application file:

        class StocksController < ApplicationController
        var myStocks = angular.module('stocksApp', ['ngTable', 'ngResource']);
         
           myStocks.factory('Stock', function($resource) {
            return $resource('stocks/:id', { id: '@id' }, {
               index: { method: 'GET', isArray: true, responseType: 'json' }
            });
           })
         
           myStocks.controller('stocksController', function($scope, $filter, ngTableParams, Stock) {
            $scope.stocks = Stock.index()
            $scope.stocksTable = new ngTableParams({
             page: 1,
              count: 10
            }, {
              total: $scope.stocks.length,
              getData: function ($defer, params) {
                $scope.data = params.sorting() ? $filter('orderBy')($scope.stocks, params.orderBy()) : $scope.stocks;
                $scope.data = $scope.data.slice((params.page() - 1) * params.count(), params.page() * params.count());
                $defer.resolve($scope.data);
              }
            });
          });

        From my app, I can only see the json data from the url rather than the tabular data format in html.

  7. Marcel

    I did use your example as a start of my development. Thank you for it.
    However since you included the lastest dist javascript, this is now broken. Your version works with 1.0.0.beta 9.

    You need to change:
    ngTableParams to NgTableParams

    the getdata has only params:

    getData: function (params) {

    and returns:

    return $scope.data;
  8. Sujan

    Are you injecting NgTableParams? In that case is accept only one parameter with params..
    use this..
    getData: function (params) {
    }

    1. Rahul

      If i will remove the $defer then what about next line $defer.resolve($scope.data);.
      Should i remove or replace with with what ?

  9. Austyns

    Nice one. The most straight forward example and implementation of datatables with pagination and sorting in angularjs

  10. Fabio

    I’m having a problem to load your code.

    $scope.users = [{'id':1,'first_name':'Philip','last_name':'Kim','email':'pkim0@mediafire.com','country':'Indonesia','ip_address':'29.107.35.8'},
                                {'id':2,'first_name':'Judith','last_name':'Austin','email':'jaustin1@mapquest.com','country':'China','ip_address':'173.65.94.30'},
                                {'id':3,'first_name':'Julie','last_name':'Wells','email':'jwells2@illinois.edu','country':'Finland','ip_address':'9.100.80.145'},
                                {'id':4,'first_name':'Gloria','last_name':'Greene','email':'ggreene3@blogs.com','country':'Indonesia','ip_address':'69.115.85.157'},
                                {'id':50,'first_name':'Andrea','last_name':'Greene','email':'agreene4@fda.gov','country':'Russia','ip_address':'128.72.13.52'}];
     
      $scope.usersTable = new NgTableParams({
                    page: 1,
                    count: 10
                }, {
                    total: $scope.users.length,
                    getData: function ($defer, params) {
                        $scope.data = $scope.users.slice((params.page() - 1) * params.count(), params.page() * params.count());
                        $defer.resolve($scope.data);
                    }
                });

    The error:
    Cannot read property ‘page’ of undefined

  11. venugopal

    impleted ngtable ; i got below error

    angular.js:13920 Error: [$injector:unpr] Unknown provider: ngTableParamsProvider <- ngTableParams <- paymentCtrl

  12. Tahisha

    I was able to get most of this working. I have the following problems. The only modifications to the code example I made were the suggestions to use “NgTableParams” vs “ngTableParams” and I removed the “$defer” command and from the parameters.

    ISSUES:
    I have the sort OPTIONS at the top, but whenever I click them, the page does not do anything
    I have the filter windows but whenever I type anything, nothing works. Also on the filter, whenever add the filter option to the table, I get an error.
    The page is paginated to be how many pages are declared but there are no pagination options below to go to the next page.

  13. ravi

    Hey guys,
    tried this example, got errors at first but changed “ngTableParams” to =>NgTableParams,
    then “function ($defer, params)” to =>function (params),
    “$defer.resolve($scope.data);” to => return $scope.data;
    every thing is fine, but i’m not getting column filter.
    getting
    Lexer Error: Unexpected next at column{1} in expression [{2}].

    1. ravi

      got it friends,
      small shitty mistake,
      that i have followed in table tag is:
      show-filter=”true” where as this should be :: => show-filter=true,

      this solved my problem.

Leave a Reply

Your email address will not be published. Required fields are marked *

Obs: Use the tag <pre lang="LANGUAGE"> to include code blocks to your comment.
Example: <pre lang="javascript"> console.log('Test'); </pre>