Forked from Two Fucking Developers's Pen AngularJS virtual list directive.
A Pen by Captain Anonymous on CodePen.
Forked from Two Fucking Developers's Pen AngularJS virtual list directive.
A Pen by Captain Anonymous on CodePen.
| <div ng-app="virtualListApp"> | |
| <div ng-controller="MainCtrl as controller" class="row"> | |
| <div class="col-lg-6 col-md-6 col-sm-6"> | |
| <ui-virtual-list ui-data-provider="controller.dataProvider" ui-on-select="controller.onSelect(option)" ng-model="controller.selectedOption"></ui-virtual-list> | |
| </div> | |
| <div class="col-lg-6 col-md-6 col-sm-6"> | |
| <div class="selectedOption"> | |
| {{controller.selectedOption | json}} | |
| </div> | |
| </div> | |
| </div> | |
| </div> | |
| <link rel="stylesheet" href="//maxcdn.bootstrapcdn.com/bootstrap/3.3.1/css/bootstrap.min.css"> | |
| <script src="https://ajax.googleapis.com/ajax/libs/angularjs/1.2.26/angular.min.js"></script> |
| 'use strict'; | |
| /** | |
| * @ngdoc overview | |
| * @name virtualListApp | |
| * @description | |
| * # virtualListApp | |
| * | |
| * Main module of the application. | |
| */ | |
| angular.module('virtualListApp', []) | |
| .controller('MainCtrl', function () { | |
| var dp = []; | |
| for (var i=0; i<1000000; i++) { | |
| dp.push({ | |
| index: i, | |
| label: "label " + i, | |
| value: "value " + i | |
| }); | |
| } | |
| this.dataProvider = dp; | |
| this.selectedOption = null; | |
| this.onSelect = function(option) { | |
| console.log(option); | |
| }; | |
| }) | |
| .directive('uiVirtualList', | |
| [function () { | |
| return { | |
| restrict: 'E', | |
| require: "ngModel", | |
| template: '<div class="canvas" ng-style="canvasHeight">\ | |
| <div class="renderer"\ | |
| ng-repeat="item in visibleProvider"\ | |
| ng-click="onClickOption(item)"\ | |
| ng-style="item.styles"\ | |
| ng-class="{selected:\ (currentOption.value == item.value)}">\ | |
| <span>{{item.label}}</span>\ | |
| </div>\ | |
| </div>', | |
| scope: { | |
| uiDataProvider: '=', | |
| uiOnSelect: '&' | |
| }, | |
| link: function (scope, elem, attrs, ngModelCtrl) { | |
| var rowHeight = 30; | |
| scope.height = 200; | |
| scope.scrollTop = 0; | |
| scope.visibleProvider = []; | |
| scope.cellsPerPage = 0; | |
| scope.numberOfCells = 0; | |
| scope.canvasHeight = {}; | |
| // Init | |
| scope.init = function () { | |
| elem[0].addEventListener('scroll', scope.onScroll); | |
| scope.cellsPerPage = Math.round(scope.height / rowHeight); | |
| scope.numberOfCells = 3 * scope.cellsPerPage; | |
| scope.canvasHeight = { | |
| height: scope.uiDataProvider.length * rowHeight + 'px' | |
| }; | |
| scope.updateDisplayList(); | |
| }; | |
| scope.updateDisplayList = function () { | |
| var firstCell = Math.max(Math.floor(scope.scrollTop / rowHeight) - scope.cellsPerPage, 0); | |
| var cellsToCreate = Math.min(firstCell + scope.numberOfCells, scope.numberOfCells); | |
| scope.visibleProvider = scope.uiDataProvider.slice(firstCell, firstCell + cellsToCreate); | |
| for (var i = 0; i < scope.visibleProvider.length; i++) { | |
| scope.visibleProvider[i].styles = { | |
| 'top': ((firstCell + i) * rowHeight) + "px" | |
| } | |
| } | |
| }; | |
| scope.onScroll = function (evt) { | |
| scope.scrollTop = elem.prop('scrollTop'); | |
| scope.updateDisplayList(); | |
| scope.$apply(); | |
| }; | |
| scope.onClickOption = function (option) { | |
| ngModelCtrl.$setViewValue(option); | |
| scope.currentOption = option; | |
| scope.uiOnSelect({"option": option}); | |
| }; | |
| scope.init(); | |
| } | |
| }; | |
| } | |
| ]); |
| .row { | |
| margin: 0 !important; | |
| } | |
| .selectedOption { | |
| width: 300px; | |
| display: inline-block; | |
| } | |
| ui-virtual-list { | |
| width: 200px; | |
| max-height: 200px; | |
| overflow-y: auto; | |
| display: block; | |
| } | |
| ui-virtual-list .canvas { | |
| background-color: #eee; | |
| position: relative; | |
| } | |
| ui-virtual-list div.renderer { | |
| display: block; | |
| width: 100%; | |
| cursor: pointer; | |
| position: absolute; | |
| height: 30px; | |
| line-height: 30px; | |
| } | |
| ui-virtual-list div.renderer span { | |
| margin-left: 10px; | |
| } | |
| ui-virtual-list div.renderer.selected { | |
| background-color: #ccc; | |
| } | |
| ui-virtual-list div.renderer:hover { | |
| background-color: #666; | |
| color: white; | |
| } |