Server-side pagination with AngularJS

by

AngularJS is one of the most used Javascript frameworks nowadays.

A characteristic of this framework is the possibility of binding input or output parts of an HTML page to a model represented by standard JavaScript variables.

Looping through arrays and collections is made easy by the ngRepeat directive.
This directive becomes handy when dealing with lists and tables, especially if associated to the AngularJS filters, which allow you to handle pagination, filtering and sorting by adding just one line of code to your html.

Unfortunately, one of the limitations of this approach is that the filtering is done client-side, therefore it wouldn’t be an optimal solution when dealing with a substantial number of rows/records.

Despite the big community and the good documentation, I wasn’t able to find a good example that explained how to implement server-side pagination with AngularJS, so I decided to write one.

Here’s a working demo of my “Tweets finder with infinite scrolling”:

DEMO

And here’s the code:


<!doctype html>
<html ng-app="Twitter">
<head>
    <meta charset="utf-8">
    <title>Tweet Search</title>
    <script src="http://ajax.googleapis.com/ajax/libs/angularjs/1.0.4/angular.min.js"></script>
    <script src="http://code.angularjs.org/angular-resource-1.0.0rc4.min.js"></script>
    <link href="http://netdna.bootstrapcdn.com/twitter-bootstrap/2.3.0/css/bootstrap-combined.min.css" rel="stylesheet">
</head>
<body>
<div ng-controller="TwitterCtrl">

    <div class="hero-unit">
        <h1><u>Tweet search</u></h1>
        <br>
        <div class="input-prepend">
            <button class="btn btn-primary" ng-click="doSearch()" type="button"><i class=""></i> Search </button>
            <button class="btn" disabled type="button">Now the latest</button>
            <input type="number" ng-model="resultsPerPage" placeholder=5 style="border-radius: 0; width: 35px"/>
            <button class="btn" disabled type="button">Tweets for</button>
            <input type="text" ng-model="searchTerm" placeholder="grio_sf"/>
        </div>

    </div>

    <div id="resultsContainer" ng-show="tweets.length > 0">
        <table class="table table-striped">
            <thead>
                <tr>
                    <th>Tweeter</th>
                    <th>Tweet</th>
                    <th>Tweet-time</th>
                </tr>
            </thead>
            <tbody>
                <tr ng-repeat="tweet in tweets">
                    <td><img src="{{tweet.profile_image_url}}" alt=""> &nbsp; {{tweet.from_user}}</td>
                    <td>{{tweet.text}}</td>
                    <td>{{tweet.created_at}}</td>
                </tr>
            </tbody>
        </table>
        <button class="btn btn-primary" ng-click="loadMore()" style="width: 100%"><i class="icon-arrow-down"></i> Load More </button>
    </div>
</div>
<script type="text/javascript">
    angular.module('Twitter', ['ngResource']);

    function TwitterCtrl($scope, $resource) {

        //stores the whole list of actual (the "results" field of the JSON response) tweets
        $scope.tweets = [];
        //stores only the last "result_per_page" tweets with all the info (original JSON response)
        $scope.lastTweetsWithInfo = null;
        //change this if you want more than 5 tweets per time
        $scope.resultsPerPage = 5;
        //start from 1, not 0
        $scope.page = 1;
        //used to avoid duplicated tweets see https://dev.twitter.com/docs/working-with-timelines
        $scope.max_id = null;
        //bound to the input text
        $scope.searchTerm = "grio_sf";

        //handles http request
        $scope.twitter = $resource('http://search.twitter.com/:action',
                {
                    action:'search.json',
                    callback:'JSON_CALLBACK',
                    page: $scope.page,
                    rpp: $scope.resultsPerPage,
                    q: $scope.searchTerm
                },
                {
                    get:{method:'JSONP'}
                }
        );

        $scope.doSearch = function () {
            $scope.lastTweetsWithInfo = $scope.twitter.get({q: $scope.searchTerm, rpp: $scope.resultsPerPage}, function(){
                //reinit the tweet list when a new search is done
                $scope.tweets = [];
                updateTweetsAndParams();
            });
        };

        $scope.loadMore = function(){
            $scope.lastTweetsWithInfo = $scope.twitter.get({q:$scope.searchTerm, max_id:$scope.max_id, page: $scope.page, rpp: $scope.resultsPerPage}, function(){
                updateTweetsAndParams();
            });

        };

        function updateTweetsAndParams(){
            //add the last tweets results
            $scope.tweets = $scope.tweets.concat($scope.lastTweetsWithInfo.results);
            //increment the page number
            $scope.page++;
            //update the last max_id for the following request
            $scope.max_id = $scope.lastTweetsWithInfo.max_id;
        }

        //do the search  for the first time
        $scope.doSearch();


    }
</script>

</body>
</html>

(Available also on our Github: https://github.com/GrioSF/angularPagination)

Don’t forget to search for @grio_sf ! ! ! !

9 Comments

  1. “AngularJS is one of the most used Javascript frameworks nowadays.”

    What? What kind of writing is this? Where is it used most? On your computer, in your office? On the web as whole? Any evidence? Thanks for that useless sentence.

Leave a Reply

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