AngularJS: Infinite Scrolling

by heavyhorse

HTML

<script src="http://ajax.googleapis.com/ajax/libs/angularjs/1.2.23/angular.min.js"></script>
<table ng-controller="StockHistoryController">
        <tbody whenScrollEnds="loadMoreRecords()">
            <tr ng-repeat="stock in stockList">
                <td>{{stock.dateValue | date:'mediumDate'}}</td>
                <td>{{stock.price | currency:'$':2}}</td>
            </tr>
        </tbody>
    </table>

CSS

thead { background: lightgray; align-content: center; }
        tbody { display: block; overflow: auto; height: 250px; border-collapse: collapse; }
        th { height: 40px; width: auto; border: 1px solid black; text-align: center; }
        td { height: 30px; width: 120px; margin: 0px; padding: 5px; border: 1px solid black;}

JavaScript

var appModule = angular.module('StockHistoryApp', []);
appModule.constant('chunkSize', 50);
appModule.controller('StockHistoryController', 
    function($scope, chunkSize) {
        $scope.stockList = [];
        var currentIndex = 0;
        var todayDate = new Date();
        $scope.loadMoreRecords = function() {
            // Mocking stock values 
            // In an real application, data would be retrieved from an
            // external system
            var stock;
            var i = 0;
            while (i < chunkSize) {
                currentIndex++;
                var newDate = new Date();
                newDate.setDate(todayDate.getDate() - currentIndex);
                if (newDate.getDay() >= 1 && newDate.getDay() <= 5) {
                    stock = {
                        dateValue: newDate,
                        price: 20.0 + Math.random() * 10
                    };
                    $scope.stockList.push(stock);
                    i++;
                }
            }
        };

        $scope.loadMoreRecords();
    });

    appModule.directive('whenscrollends', function() {        
        return {
            restrict: "A",
            link: function(scope, element, attrs) {
                var visibleHeight = element.height();
                var threshold = 100;

                element.scroll(function() {
                    var scrollableHeight = element.prop('scrollHeight');
                    var hiddenContentHeight = scrollableHeight - visibleHeight;

                    if (hiddenContentHeight - element.scrollTop() <= threshold) {
                        // Scroll is almost at the bottom. Loading more rows
                        scope.$apply(attrs.whenscrollends);
                    }
                });
            }
        };
    });