Skip to content

Instantly share code, notes, and snippets.

@dzNavitski
Forked from scyrizales/SimpleVirtualRepeater.js
Created October 3, 2016 14:29
Show Gist options
  • Select an option

  • Save dzNavitski/8f62b7e09f5976700656af13239bed0e to your computer and use it in GitHub Desktop.

Select an option

Save dzNavitski/8f62b7e09f5976700656af13239bed0e to your computer and use it in GitHub Desktop.
SimpleVirtualRepeater - This is an simple solution to handle thousands of results on an ng-repeat without sacrificing performance.
(function() {
'use strict';
angular.module('simple-virtual-repeater', [])
.directive('virtualRepeater', virtualRepeater);
virtualRepeater.$inject = ['$compile', '$timeout'];
function virtualRepeater($compile, $timeout) {
var directive = {
restrict: 'EA',
replace: 'true',
transclude: true,
template: '<div class="virtual-repeat"><div class="virtual-repeat-before"></div><div ng-transclude=""></div><div class="virtual-repeat-after"></div></div>',
link: function postLink(scope, iElement, iAttrs, controller) {
var internalRepeat = iElement.find("[ng-transclude]"),
beforeRepeat = iElement.find(".virtual-repeat-before"),
afterRepeat = iElement.find(".virtual-repeat-after"),
parent = iElement.parent();
internalRepeat.hide();
var expressionMatches = /^\s*(\S+)\s+in\s+([\S\s]+?)(track\s+by\s+\S+)?$/.exec(iAttrs.virtualRepeat),
lhs = expressionMatches[1],
rhs = expressionMatches[2],
rhsSuffix = expressionMatches[3] || '';
var itemsAllowed = +(iAttrs.itemsAllowed || 5), totalItems = [], itemHeight = 0;
var repeater = angular.element('<div class="virtual-repeat-item" ng-repeat="' + lhs + ' in virtualRepeatCollection ' + rhsSuffix + '"></div>');
repeater.html(internalRepeat.html());
scope.virtualRepeatCollection = [];
scope.$watchCollection(rhs, function (data) {
if (data) {
totalItems = data;
scope.virtualRepeatCollection = totalItems.slice(0, itemsAllowed);
$timeout(function () {
itemHeight = iElement.find(".virtual-repeat-item:first").height();
parent.scrollTop(0);
beforeRepeat.css("height", 0);
afterRepeat.css("height", itemHeight * (totalItems.length - itemsAllowed));
});
}
});
internalRepeat.after($compile(repeater)(scope));
parent.on('scroll', function () {
var movedDistance = parent.scrollTop(),
movedItems = Math.floor(movedDistance / itemHeight);
movedItems = (movedItems > 0)? movedItems - 1 : 0;
scope.virtualRepeatCollection = totalItems.slice(movedItems, movedItems + itemsAllowed);
beforeRepeat.css("height", itemHeight * (movedItems));
afterRepeat.css("height", itemHeight * (totalItems.length - movedItems - itemsAllowed));
scope.$apply();
});
}
};
return directive;
};
})();
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment