Skip to content

Instantly share code, notes, and snippets.

Created May 7, 2015 09:10
Show Gist options
  • Select an option

  • Save anonymous/a008a255be365e7e11e7 to your computer and use it in GitHub Desktop.

Select an option

Save anonymous/a008a255be365e7e11e7 to your computer and use it in GitHub Desktop.
AngularJS virtual list directive
<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;
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment