Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

How can I make an virtual scroll with angularJS?

I'm trying to make a directive that I can do a virtual scroll, so as the user scrolls the table, the table remove "old" views and add "new" views, kind like of collection repeat but I've been failing, I think I didn't understand the math behind it, can someone help me?

this is my directive code:

BaseModule.directive('myScroll', function() {
    return {
        restrict:"A",
        scope:{
            rows:"=",
            headers:"="
        },
        link: function(scope,el) {
            var scrollTop = 0;
            var scrollLeft = 0;
            angular.element(el).on('scroll',function(){
                scrollTop = $(el).scrollTop();
                scrollLeft = $(el).scrollLeft();
                $(el).parent().find(".header").scrollLeft(scrollLeft);
                var height = $(el).height();
                var numberOfRows = height/23;
                var initialRow = scrollTop/23;
                var html = "";
                for(i=0; i<numberOfRows;i++){
                    var row = scope.rows[i+initialRow];
                    html = html + addRow(row,i+initialRow);
                }
                $(el).find('.tbody-scroll').append(html);
            });
            scope.$watch('rows',function(rows){
                var height = $(el).height();
                var numberOfRows = height/23;
                var initialRow = scrollTop/23;
                var html = "";
                for(i=0; i<numberOfRows;i++){
                    var row = rows[i+initialRow];
                    html = html + addRow(row,i+initialRow);
                }
                $(el).find('.tbody-scroll').append(html);
            });
            var addRow = function(row,index){
                var html = "";
                var pos = 0;
                var totalWidth = 0;
                angular.forEach(row,function(col){
                    var width = scope.headers[pos].width;
                    totalWidth = totalWidth + width;
                    html = html + "<span style='width:"+width+"px'>"+col.value+"</span>";
                    pos++;
                });
                html = "<div class='row' style='top:"+index*23+"px;width:"+totalWidth+"px;'>"+html;
                html = html + "</div>";
                return html;
            };
        }
    };
});

<!-- my directive .html -->
<div class="mTable">
    <div class="header" ng-style="headerWidth(headers())">
        <span ng-repeat="header in headers()" ng-style="widthStyle(header)">
            {{::header.label}}
        </span>
    </div>
    <div class="tbody-container" my-scroll headers="headers()" rows="rows()">
        <div class="tbody-scroll" ng-style="scrollHeight(rows(),headers())"></div>
    </div>
</div>
like image 876
João Pedro Segurado Avatar asked Oct 21 '15 12:10

João Pedro Segurado


People also ask

What is virtual scrolling in angular?

Loading hundreds of elements can be slow in any browser; virtual scrolling enables a performant way to simulate all items being rendered by making the height of the container element the same as the height of total number of elements to be rendered, and then only rendering the items in view.

What is virtual scrolling Javascript?

Allows to load the large amounts of data without any performance degradation by rendering rows and columns only in the current content viewport. Rest of the aggregated data will be brought into viewport dynamically based on vertical or horizontal scroll position.

How infinite scroll is implemented in AngularJS?

ngInfiniteScroll is a directive that you can use to implement infinite scrolling in your AngularJS applications. Simply declare which function to call when the user gets close to the bottom of the content with the directive and the module will take care of the rest.

When should I use virtual scroll?

Virtual scrolling is widely used in large data grids that have hundreds of thousands or millions of rows and tens or hundreds of columns. In a virtual scrolling strategy, the total number of elements remains the same as the user scrolls, just that the current ones are replaced with the next ones.


2 Answers

Giving a full answer with code might require a bit too much of an effort
This library implements virtual scroll on ng-repeat https://github.com/stackfull/angular-virtual-scroll in the description there's also an article on how to implement this feature on your own.

The basic concept is to make two divs, one above and one below the list, which size is determined by the number of elements inside the list (this approach has a limitation since list elements must either have all the same height or their height must be fixed), then you delete elements as they disappear from the viewport and resize the divs according to the number of elements not currently rendered and your position on the list

like image 74
valepu Avatar answered Sep 30 '22 18:09

valepu


Not a direct answer to your question, but an alternative: You may want to look at the ui-scroll directive which is a replacement for ng-repeat and has a similar function.

Example in your controller

$scope.movieDataSource = {

    get : function (index, count, callback) {
        var i, items = [$scope.userMovies], item;

            var min = 1;
            var max = 1000;

        for (i=index ; i<index + count ; i++) {
                if(i < min || i > max) {
                    continue;
                }
            item = {
                title: $scope.userMovies.title,
                imageURL: $scope.userMovies.poster_path
            };
            items.push (item);
        }
        callback (items);
    }
}

And in your view:

<div ui-scroll="item in movieDataSource">
  {{item.title}}
</div>
like image 22
Andre Kreienbring Avatar answered Sep 30 '22 16:09

Andre Kreienbring