Tutorial: ng-table with infinite scroll

I’ve already showed in this blog how to create a basic datatable with ng-table, for those who didn’t see it yet, just click on the link. This tutorial will just be a complement to the previous one, the difference is that instead of using pagination I’m going to use infinite scroll, and don’t worry, I’ll also keep the sorting and filtering features.

So before we start let’s just put the links to every script we need, your index.html should look like this:

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

As you can see I just put the links to: JQuery, Angular, bootstrap, ng-table and ngInfiniteScroll. There’s also the app.js and style.css, which I created to put my code on them.

Note that the body is still empty for now, let’s leave it like this and open our app.js, the first thing we need to do is to create our angular module and controller, just copy the following code to your app.js:

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

Don’t forget to declare the ngTable and infinite-scroll as dependencies, we’re going to use them later. This code is still very simple, I just created a module called ngTableTutorial, if you go back to the index.html code you’ll see that the ng-app=”ngTableTutorial” is already there in the html tag, and I also created a controller called tableController, again if go to the index.html there will be a div inside our body with the attribute ng-controller=”tableController”.

Now we need some data to be displayed to the table, I personally like mockaroo to generate random data, but feel free to generate it as you like, you’ll need about 1000 rows for this tutorial, after you generate it, just put it in a variable inside you controller, like this:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
$scope.users =
        [{
                "id": 1,
                "first_name": "Theresa",
                "last_name": "Morris",
                "email": "tmorris0@myspace.com",
                "country": "Indonesia",
                "ip_address": "143.220.154.199"
            }, {
                "id": 2,
                "first_name": "Steve",
                "last_name": "Gray",
                "email": "sgray1@nytimes.com",
                "country": "Norway",
                "ip_address": "163.199.165.94"
            }
           .
           .
           .
            {
                "id": 1000,
                "first_name": "Gloria",
                "last_name": "West",
                "email": "gwest2@go.com",
                "country": "China",
                "ip_address": "16.171.225.220"
            }
];

Now that we have the data we’re ready to create our table, copy the table bellow inside your div with the ng-controller attribute:

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

Each column is displaying one attribute of our JSON, I put the attribute sortable and filter in some of them to add the sorting and filtering features to the datatable (to show the filter you also have to put show-filter=”true” in your table). But what is important here is the attributes ng-table=”tableParams” and infinite-scroll=”getMoreData()” from the table, the first is binding the table to the tableParams variable in our controller (I’m still going to create this variable), and the second attribute receives the method that will be called when the user reaches the bottom of the page, that’s the method that will make our infinite scroll work.

Now the only thing left for us to do is to create our tableParams and implement the getMoreData() method, copy the following code bellow our JSON in your controller:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
$scope.tableParams = new ngTableParams({
    page: 1,
    count: $scope.users.length
}, {
    counts: [],
    total: 1,
    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(0, 20);
        $defer.resolve($scope.data);
    }
});
 
$scope.getMoreData = function () {
    $scope.data = $scope.users.slice(0, $scope.data.length + 20);
}

In this code we are instantiating the ngTableParams, the fist object it receives as a parameter is just defining that the current page is 1 and setting the row count, but what really matters here is the function getData, it will be called on the table initialization and also every time we sort or filter it, the lines 8 and 9 contains the logic to sort and filter the data, note that in line 10 I’m getting only the first 20 rows of our data, I’m doing this because every time this method is called, or the user will be filtering the data or he’ll be sorting it, both actions require him to be on the top of the page, thus I don’t need to show more than 20 rows.

Ok, now we just need to load more rows when he reaches the bottom of the pages, take a look at line 16, it’s just adding 20 more rows to our data, note that I’m using 2 variables here: $scope.data and $scope.users. The last one contains our original data, we cannot modify it, otherwise we’ll lose the data, that’s why we need an auxiliary variable, just to manipulate the data.

That’s it, now if you run your project you should see the following result:

ngTable with Infinite scroll
ng-Table with infinite scroll

As you scroll down you’ll see that the scroll bar will get smaller and smaller.

Tutorial: Implementing Infinite Scroll with AngularJS and ngInfiniteScroll

Over the past few years the infinite scroll has became very popular across the web, developers are increasingly choosing to use infinite scroll over the conventional paginator. The advantage is that it doesn’t require the user to manually go to the next page when he reaches the end of the page, it automatically loads and display more data without the user intervention.

In this tutorial I’m going to show how to implement infinite scroll using ngInfiniteScroll for AngularJS.

First create the js and html file:

app.js

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
angular.module('infiniteScrollTutorial', ['infinite-scroll'])
        .controller('infiniteScrollController', function ($scope, $http) {
            $scope.users =
                    [{
                            "id": 1,
                            "first_name": "Kimberly",
                            "last_name": "Grant",
                            "email": "kgrant0@ebay.co.uk",
                            "country": "Bolivia",
                            "ip_address": "93.77.148.179"
                        }, {
                            "id": 2,
                            "first_name": "Elizabeth",
                            "last_name": "Lewis",
                            "email": "elewis1@so-net.ne.jp",
                            "country": "Indonesia",
                            "ip_address": "39.187.159.25"
                        },
                        .
                        .
                        .
 
                        {
                            "id": 100,
                            "first_name": "Shawn",
                            "last_name": "Ellis",
                            "email": "sellis2r@diigo.com",
                            "country": "Portugal",
                            "ip_address": "121.250.152.235"
                        }];
});

index.html

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
<!DOCTYPE html>
<html ng-app="infiniteScrollTutorial">
    <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://code.jquery.com/jquery-2.1.4.min.js"></script>
        <script src="http://cdnjs.cloudflare.com/ajax/libs/angular.js/1.4.2/angular.js"></script>
        <script src="https://raw.githubusercontent.com/BinaryMuse/ngInfiniteScroll/1.0.0/build/ng-infinite-scroll.min.js"></script>
        <script src="app/resources/js/app.js" type="text/javascript"></script>
        <style>
            .userContainer{
                width:500px;
                height:110px;
                background: #f9f9f9;
                padding: 5px;
                font-family: verdana;
                margin-bottom: 7px;
                box-shadow: 0px 0px 2px 1px;
            }
            .userContainer p{
                font-size: 12px;
            }
        </style>
    </head>
    <body>
        <div ng-controller="infiniteScrollController">
            <div >
                <div ng-repeat="user in users" class="userContainer">
                    <h4>{{user.first_name}} {{user.last_name}}</h4>
                    <p>
                        <b>Email:</b> {{user.email}}  -   
                        <b>Country:</b> {{user.country}}  -  
                        <b>IP:</b> {{user.ip_address}} 
                    </p>
                </div>
            </div>
        </div>
    </body>
</html>

Nothing special for now, except that I’ve already added the dependency ‘infinite-scroll’ in the angular module declaration, besides that we just have a regular ng-repeat iterating over a JSON (you should make this JSON as big as you can, it will be easier for you to see the results, you can use mockaroo to gerenate some JSON data).

Now let’s change the code a little bit to make the infinite scroll work, we’re going to add the attribute ‘infinite-scroll’ in the div above the one with the ng-repeat, after the modification it should look like this:

1
2
3
4
5
6
7
8
9
10
<div infinite-scroll="getMoreData()">
    <div ng-repeat="user in data" class="userContainer">
        <h4>{{user.first_name}} {{user.last_name}}</h4>
        <p>
            <b>Email:</b> {{user.email}}  -   
            <b>Country:</b> {{user.country}}  -  
            <b>IP:</b> {{user.ip_address}} 
        </p>
    </div>
</div>

Note that the new attribute is referencing the function getMoreData(), which will be called every time the bottom of the element approaches the bottom of the browser window, in this function we’ll have to write the code to get more data, also note the I’m not using the variable ‘users’ anymore in the ng-repeat, instead I’m using the auxiliary variable ‘data’.

Let’s take a look at the getMoreData() code, add this bellow the JSON in your app.js:

1
2
3
4
$scope.data = $scope.users.slice(0, 5);
$scope.getMoreData = function () {
    $scope.data = $scope.users.slice(0, $scope.data.length + 5);
}

I’m initializing the $scope.data with the 5 first elements of the $scope.users, and the function getMoreData is just adding five more elements every time it gets called.

Now if you run you application you’ll see the following result:

AngularJS infinite Scroll
AngularJS infinite Scroll

That’s it! At first it’ll have only 5 elements loaded and as you scroll down it will start loading more.

Related Posts:
Tutorial: Basic DataTable (sorting, filtering and pagination) with AngularJS and ng-Table
Tutorial: Creating Reusable Code with AngularJS Directives