Let's say I have a lot (3000+) of items I want to render (in a ng-repeat
) in a div with a fixed height and overflow: auto
, so I'd get N
visible items and a scrollbar for the rest of them.
I'm guessing doing a simple ng-repeat
with so many items will probably take a lot of time. Is there a way I can make AngularJS render only those visible N
items?
Edit:
An infinite scroll is not what I want. I want the user to be able to scroll to any point of the list, so I literally want a text editor-like behavior. Said with other words: I'd like the scroll to contain the "height" of all the items, but place in the DOM just a few ones.
This answer provides an approach for lazy-rendering only items currently in-view, as defined by the edit to the original question. I want the user to be able to scroll to any point of the list, so I literally want a text editor-like behavior. Said with other words: I'd like the scroll to contain the "height" of all the items, but place in the DOM just a few ones.
Install the angular-inview
plugin before trying this.
In order to get your scrollheight you'd need something holding the space for your array items. So I'd start with an array of 3000 simple items (or combine with infinite scroll to whatever extent you want.)
var $app = angular.module('app', ['infinite-scroll']);
$app.controller('listingController', function($scope, $window) {
$scope.listOfItems = new Array($window._bootstrappedData.length);
$scope.loadItem = function($index,$inview) {
if($inview) {
$scope.listOfItems[$index] = $window._bootstrappedData[$index];
}
}
});
Since we're talking about flexible heights, I would create a placeholder for what your content looks like pre-render.
<div ng-controller="listingController">
<ul>
<li ng-repeat="item in listOfItems track by $index" in-view="loadItem($index,$inview)" style="min-height:100px"><div ng-if="item">{{item.name}}</div></li>
</ul>
</div>
Using ng-if
will prevent rendering logic from being run unnecessarily. When you scroll an item into view, it'll automatically display. If you want to wait a second to see if the user is still scrolling you could set a timeout in the loadItem
method that cancels if the same index gets pushed out of view within a reasonable time period.
Note: If you truly wanted to avoid putting anything in the DOM, you could set your scrollable area to a specific multiple of your "placeholder" height. Then you could create a directive that uses that height to determine the indexes of the items that should be displayed. As soon as you display new items, you'd need to add their heights to the total and make sure you position them at the right spot and make sure your directive knows how to interpret those heights into evaluating the next set of displayed elements. But I think that's way too radical and unnecessary.