angular2-virtual-scroll
Advanced tools
Comparing version 0.1.5 to 0.1.6
# v0.1.6 | ||
* improve performance by using Observables for scroll event | ||
* add attribute selector | ||
* fixes #39 - infinite event loop with empty items array | ||
# v0.1.5 | ||
@@ -3,0 +9,0 @@ |
import { ElementRef, EventEmitter, OnChanges, OnDestroy, OnInit, Renderer, SimpleChanges } from '@angular/core'; | ||
import { Subject } from 'rxjs/Rx'; | ||
export interface ChangeEvent { | ||
@@ -19,2 +20,3 @@ start?: number; | ||
contentElementRef: ElementRef; | ||
scroll$: Subject<Event>; | ||
onScrollListener: Function; | ||
@@ -27,2 +29,3 @@ topPadding: number; | ||
constructor(element: ElementRef, renderer: Renderer); | ||
onScroll(e: Event): void; | ||
ngOnInit(): void; | ||
@@ -29,0 +32,0 @@ ngOnChanges(changes: SimpleChanges): void; |
@@ -12,2 +12,3 @@ "use strict"; | ||
var core_1 = require("@angular/core"); | ||
var Rx_1 = require("rxjs/Rx"); | ||
var common_1 = require("@angular/common"); | ||
@@ -23,6 +24,14 @@ var VirtualScrollComponent = (function () { | ||
this.end = new core_1.EventEmitter(); | ||
this.scroll$ = new Rx_1.Subject(); | ||
this.startupLoop = true; | ||
} | ||
VirtualScrollComponent.prototype.onScroll = function (e) { | ||
this.scroll$.next(); | ||
}; | ||
VirtualScrollComponent.prototype.ngOnInit = function () { | ||
this.onScrollListener = this.renderer.listen(this.element.nativeElement, 'scroll', this.refresh.bind(this)); | ||
var _this = this; | ||
this.scroll$.switchMap(function () { | ||
_this.refresh(); | ||
return Rx_1.Observable.of(); | ||
}).subscribe(); | ||
this.scrollbarWidth = 0; // this.element.nativeElement.offsetWidth - this.element.nativeElement.clientWidth; | ||
@@ -34,2 +43,6 @@ this.scrollbarHeight = 0; // this.element.nativeElement.offsetHeight - this.element.nativeElement.clientHeight; | ||
this.previousEnd = undefined; | ||
var items = changes.items || {}; | ||
if (changes.items != undefined && items.previousValue == undefined || items.previousValue.length === 0) { | ||
this.startupLoop = true; | ||
} | ||
this.refresh(); | ||
@@ -47,3 +60,4 @@ }; | ||
VirtualScrollComponent.prototype.refresh = function () { | ||
requestAnimationFrame(this.calculateItems.bind(this)); | ||
var _this = this; | ||
requestAnimationFrame(function () { return _this.calculateItems(); }); | ||
}; | ||
@@ -89,3 +103,4 @@ VirtualScrollComponent.prototype.scrollInto = function (item) { | ||
var itemsPerCol = Math.max(1, Math.floor(viewHeight / childHeight)); | ||
if (itemsPerCol === 1 && Math.floor(el.scrollTop / this.scrollHeight * itemCount) + itemsPerRowByCalc >= itemCount) { | ||
var scrollTop = Math.max(0, el.scrollTop); | ||
if (itemsPerCol === 1 && Math.floor(scrollTop / this.scrollHeight * itemCount) + itemsPerRowByCalc >= itemCount) { | ||
itemsPerRow = itemsPerRowByCalc; | ||
@@ -112,3 +127,4 @@ } | ||
} | ||
var indexByScrollTop = el.scrollTop / this.scrollHeight * d.itemCount / d.itemsPerRow; | ||
var scrollTop = Math.max(0, el.scrollTop); | ||
var indexByScrollTop = scrollTop / this.scrollHeight * d.itemCount / d.itemsPerRow; | ||
var end = Math.min(d.itemCount, Math.ceil(indexByScrollTop) * d.itemsPerRow + d.itemsPerRow * (d.itemsPerCol + 1)); | ||
@@ -123,2 +139,4 @@ var maxStartEnd = end; | ||
this.topPadding = d.childHeight * Math.ceil(start / d.itemsPerRow); | ||
start = !isNaN(start) ? start : -1; | ||
end = !isNaN(end) ? end : -1; | ||
if (start !== this.previousStart || end !== this.previousEnd) { | ||
@@ -191,5 +209,12 @@ // update the scroll list | ||
], VirtualScrollComponent.prototype, "contentElementRef", void 0); | ||
__decorate([ | ||
core_1.HostListener('scroll'), | ||
__metadata("design:type", Function), | ||
__metadata("design:paramtypes", [Event]), | ||
__metadata("design:returntype", void 0) | ||
], VirtualScrollComponent.prototype, "onScroll", null); | ||
VirtualScrollComponent = __decorate([ | ||
core_1.Component({ | ||
selector: 'virtual-scroll', | ||
selector: 'virtual-scroll,[virtualScroll]', | ||
exportAs: 'virtualScroll', | ||
template: "\n <div class=\"total-padding\" [style.height]=\"scrollHeight + 'px'\"></div>\n <div class=\"scrollable-content\" #content [style.transform]=\"'translateY(' + topPadding + 'px)'\">\n <ng-content></ng-content>\n </div>\n ", | ||
@@ -196,0 +221,0 @@ styles: ["\n :host {\n overflow: hidden;\n overflow-y: auto;\n position: relative;\n -webkit-overflow-scrolling: touch;\n }\n .scrollable-content {\n top: 0;\n left: 0;\n width: 100%;\n height: 100%;\n position: absolute;\n }\n .total-padding {\n width: 1px;\n opacity: 0;\n }\n "] |
@@ -1,1 +0,1 @@ | ||
[{"__symbolic":"module","version":3,"metadata":{"VirtualScrollComponent":{"__symbolic":"class","decorators":[{"__symbolic":"call","expression":{"__symbolic":"reference","module":"@angular/core","name":"Component"},"arguments":[{"selector":"virtual-scroll","template":"\n <div class=\"total-padding\" [style.height]=\"scrollHeight + 'px'\"></div>\n <div class=\"scrollable-content\" #content [style.transform]=\"'translateY(' + topPadding + 'px)'\">\n <ng-content></ng-content>\n </div>\n ","styles":["\n :host {\n overflow: hidden;\n overflow-y: auto;\n position: relative;\n -webkit-overflow-scrolling: touch;\n }\n .scrollable-content {\n top: 0;\n left: 0;\n width: 100%;\n height: 100%;\n position: absolute;\n }\n .total-padding {\n width: 1px;\n opacity: 0;\n }\n "]}]}],"members":{"items":[{"__symbolic":"property","decorators":[{"__symbolic":"call","expression":{"__symbolic":"reference","module":"@angular/core","name":"Input"}}]}],"scrollbarWidth":[{"__symbolic":"property","decorators":[{"__symbolic":"call","expression":{"__symbolic":"reference","module":"@angular/core","name":"Input"}}]}],"scrollbarHeight":[{"__symbolic":"property","decorators":[{"__symbolic":"call","expression":{"__symbolic":"reference","module":"@angular/core","name":"Input"}}]}],"childWidth":[{"__symbolic":"property","decorators":[{"__symbolic":"call","expression":{"__symbolic":"reference","module":"@angular/core","name":"Input"}}]}],"childHeight":[{"__symbolic":"property","decorators":[{"__symbolic":"call","expression":{"__symbolic":"reference","module":"@angular/core","name":"Input"}}]}],"update":[{"__symbolic":"property","decorators":[{"__symbolic":"call","expression":{"__symbolic":"reference","module":"@angular/core","name":"Output"}}]}],"change":[{"__symbolic":"property","decorators":[{"__symbolic":"call","expression":{"__symbolic":"reference","module":"@angular/core","name":"Output"}}]}],"start":[{"__symbolic":"property","decorators":[{"__symbolic":"call","expression":{"__symbolic":"reference","module":"@angular/core","name":"Output"}}]}],"end":[{"__symbolic":"property","decorators":[{"__symbolic":"call","expression":{"__symbolic":"reference","module":"@angular/core","name":"Output"}}]}],"contentElementRef":[{"__symbolic":"property","decorators":[{"__symbolic":"call","expression":{"__symbolic":"reference","module":"@angular/core","name":"ViewChild"},"arguments":["content",{"read":{"__symbolic":"reference","module":"@angular/core","name":"ElementRef"}}]}]}],"__ctor__":[{"__symbolic":"constructor","parameters":[{"__symbolic":"reference","module":"@angular/core","name":"ElementRef"},{"__symbolic":"reference","module":"@angular/core","name":"Renderer"}]}],"ngOnInit":[{"__symbolic":"method"}],"ngOnChanges":[{"__symbolic":"method"}],"ngOnDestroy":[{"__symbolic":"method"}],"refresh":[{"__symbolic":"method"}],"scrollInto":[{"__symbolic":"method"}],"countItemsPerRow":[{"__symbolic":"method"}],"calculateDimensions":[{"__symbolic":"method"}],"calculateItems":[{"__symbolic":"method"}]}},"VirtualScrollModule":{"__symbolic":"class","decorators":[{"__symbolic":"call","expression":{"__symbolic":"reference","module":"@angular/core","name":"NgModule"},"arguments":[{"imports":[{"__symbolic":"reference","module":"@angular/common","name":"CommonModule"}],"exports":[{"__symbolic":"reference","name":"VirtualScrollComponent"}],"declarations":[{"__symbolic":"reference","name":"VirtualScrollComponent"}]}]}]}}},{"__symbolic":"module","version":1,"metadata":{"VirtualScrollComponent":{"__symbolic":"class","decorators":[{"__symbolic":"call","expression":{"__symbolic":"reference","module":"@angular/core","name":"Component"},"arguments":[{"selector":"virtual-scroll","template":"\n <div class=\"total-padding\" [style.height]=\"scrollHeight + 'px'\"></div>\n <div class=\"scrollable-content\" #content [style.transform]=\"'translateY(' + topPadding + 'px)'\">\n <ng-content></ng-content>\n </div>\n ","styles":["\n :host {\n overflow: hidden;\n overflow-y: auto;\n position: relative;\n -webkit-overflow-scrolling: touch;\n }\n .scrollable-content {\n top: 0;\n left: 0;\n width: 100%;\n height: 100%;\n position: absolute;\n }\n .total-padding {\n width: 1px;\n opacity: 0;\n }\n "]}]}],"members":{"items":[{"__symbolic":"property","decorators":[{"__symbolic":"call","expression":{"__symbolic":"reference","module":"@angular/core","name":"Input"}}]}],"scrollbarWidth":[{"__symbolic":"property","decorators":[{"__symbolic":"call","expression":{"__symbolic":"reference","module":"@angular/core","name":"Input"}}]}],"scrollbarHeight":[{"__symbolic":"property","decorators":[{"__symbolic":"call","expression":{"__symbolic":"reference","module":"@angular/core","name":"Input"}}]}],"childWidth":[{"__symbolic":"property","decorators":[{"__symbolic":"call","expression":{"__symbolic":"reference","module":"@angular/core","name":"Input"}}]}],"childHeight":[{"__symbolic":"property","decorators":[{"__symbolic":"call","expression":{"__symbolic":"reference","module":"@angular/core","name":"Input"}}]}],"update":[{"__symbolic":"property","decorators":[{"__symbolic":"call","expression":{"__symbolic":"reference","module":"@angular/core","name":"Output"}}]}],"change":[{"__symbolic":"property","decorators":[{"__symbolic":"call","expression":{"__symbolic":"reference","module":"@angular/core","name":"Output"}}]}],"start":[{"__symbolic":"property","decorators":[{"__symbolic":"call","expression":{"__symbolic":"reference","module":"@angular/core","name":"Output"}}]}],"end":[{"__symbolic":"property","decorators":[{"__symbolic":"call","expression":{"__symbolic":"reference","module":"@angular/core","name":"Output"}}]}],"contentElementRef":[{"__symbolic":"property","decorators":[{"__symbolic":"call","expression":{"__symbolic":"reference","module":"@angular/core","name":"ViewChild"},"arguments":["content",{"read":{"__symbolic":"reference","module":"@angular/core","name":"ElementRef"}}]}]}],"__ctor__":[{"__symbolic":"constructor","parameters":[{"__symbolic":"reference","module":"@angular/core","name":"ElementRef"},{"__symbolic":"reference","module":"@angular/core","name":"Renderer"}]}],"ngOnInit":[{"__symbolic":"method"}],"ngOnChanges":[{"__symbolic":"method"}],"ngOnDestroy":[{"__symbolic":"method"}],"refresh":[{"__symbolic":"method"}],"scrollInto":[{"__symbolic":"method"}],"countItemsPerRow":[{"__symbolic":"method"}],"calculateDimensions":[{"__symbolic":"method"}],"calculateItems":[{"__symbolic":"method"}]}},"VirtualScrollModule":{"__symbolic":"class","decorators":[{"__symbolic":"call","expression":{"__symbolic":"reference","module":"@angular/core","name":"NgModule"},"arguments":[{"imports":[{"__symbolic":"reference","module":"@angular/common","name":"CommonModule"}],"exports":[{"__symbolic":"reference","name":"VirtualScrollComponent"}],"declarations":[{"__symbolic":"reference","name":"VirtualScrollComponent"}]}]}]}}}] | ||
[{"__symbolic":"module","version":3,"metadata":{"VirtualScrollComponent":{"__symbolic":"class","decorators":[{"__symbolic":"call","expression":{"__symbolic":"reference","module":"@angular/core","name":"Component"},"arguments":[{"selector":"virtual-scroll,[virtualScroll]","exportAs":"virtualScroll","template":"\n <div class=\"total-padding\" [style.height]=\"scrollHeight + 'px'\"></div>\n <div class=\"scrollable-content\" #content [style.transform]=\"'translateY(' + topPadding + 'px)'\">\n <ng-content></ng-content>\n </div>\n ","styles":["\n :host {\n overflow: hidden;\n overflow-y: auto;\n position: relative;\n -webkit-overflow-scrolling: touch;\n }\n .scrollable-content {\n top: 0;\n left: 0;\n width: 100%;\n height: 100%;\n position: absolute;\n }\n .total-padding {\n width: 1px;\n opacity: 0;\n }\n "]}]}],"members":{"items":[{"__symbolic":"property","decorators":[{"__symbolic":"call","expression":{"__symbolic":"reference","module":"@angular/core","name":"Input"}}]}],"scrollbarWidth":[{"__symbolic":"property","decorators":[{"__symbolic":"call","expression":{"__symbolic":"reference","module":"@angular/core","name":"Input"}}]}],"scrollbarHeight":[{"__symbolic":"property","decorators":[{"__symbolic":"call","expression":{"__symbolic":"reference","module":"@angular/core","name":"Input"}}]}],"childWidth":[{"__symbolic":"property","decorators":[{"__symbolic":"call","expression":{"__symbolic":"reference","module":"@angular/core","name":"Input"}}]}],"childHeight":[{"__symbolic":"property","decorators":[{"__symbolic":"call","expression":{"__symbolic":"reference","module":"@angular/core","name":"Input"}}]}],"update":[{"__symbolic":"property","decorators":[{"__symbolic":"call","expression":{"__symbolic":"reference","module":"@angular/core","name":"Output"}}]}],"change":[{"__symbolic":"property","decorators":[{"__symbolic":"call","expression":{"__symbolic":"reference","module":"@angular/core","name":"Output"}}]}],"start":[{"__symbolic":"property","decorators":[{"__symbolic":"call","expression":{"__symbolic":"reference","module":"@angular/core","name":"Output"}}]}],"end":[{"__symbolic":"property","decorators":[{"__symbolic":"call","expression":{"__symbolic":"reference","module":"@angular/core","name":"Output"}}]}],"contentElementRef":[{"__symbolic":"property","decorators":[{"__symbolic":"call","expression":{"__symbolic":"reference","module":"@angular/core","name":"ViewChild"},"arguments":["content",{"read":{"__symbolic":"reference","module":"@angular/core","name":"ElementRef"}}]}]}],"__ctor__":[{"__symbolic":"constructor","parameters":[{"__symbolic":"reference","module":"@angular/core","name":"ElementRef"},{"__symbolic":"reference","module":"@angular/core","name":"Renderer"}]}],"onScroll":[{"__symbolic":"method","decorators":[{"__symbolic":"call","expression":{"__symbolic":"reference","module":"@angular/core","name":"HostListener"},"arguments":["scroll"]}]}],"ngOnInit":[{"__symbolic":"method"}],"ngOnChanges":[{"__symbolic":"method"}],"ngOnDestroy":[{"__symbolic":"method"}],"refresh":[{"__symbolic":"method"}],"scrollInto":[{"__symbolic":"method"}],"countItemsPerRow":[{"__symbolic":"method"}],"calculateDimensions":[{"__symbolic":"method"}],"calculateItems":[{"__symbolic":"method"}]}},"VirtualScrollModule":{"__symbolic":"class","decorators":[{"__symbolic":"call","expression":{"__symbolic":"reference","module":"@angular/core","name":"NgModule"},"arguments":[{"imports":[{"__symbolic":"reference","module":"@angular/common","name":"CommonModule"}],"exports":[{"__symbolic":"reference","name":"VirtualScrollComponent"}],"declarations":[{"__symbolic":"reference","name":"VirtualScrollComponent"}]}]}]}}},{"__symbolic":"module","version":1,"metadata":{"VirtualScrollComponent":{"__symbolic":"class","decorators":[{"__symbolic":"call","expression":{"__symbolic":"reference","module":"@angular/core","name":"Component"},"arguments":[{"selector":"virtual-scroll,[virtualScroll]","exportAs":"virtualScroll","template":"\n <div class=\"total-padding\" [style.height]=\"scrollHeight + 'px'\"></div>\n <div class=\"scrollable-content\" #content [style.transform]=\"'translateY(' + topPadding + 'px)'\">\n <ng-content></ng-content>\n </div>\n ","styles":["\n :host {\n overflow: hidden;\n overflow-y: auto;\n position: relative;\n -webkit-overflow-scrolling: touch;\n }\n .scrollable-content {\n top: 0;\n left: 0;\n width: 100%;\n height: 100%;\n position: absolute;\n }\n .total-padding {\n width: 1px;\n opacity: 0;\n }\n "]}]}],"members":{"items":[{"__symbolic":"property","decorators":[{"__symbolic":"call","expression":{"__symbolic":"reference","module":"@angular/core","name":"Input"}}]}],"scrollbarWidth":[{"__symbolic":"property","decorators":[{"__symbolic":"call","expression":{"__symbolic":"reference","module":"@angular/core","name":"Input"}}]}],"scrollbarHeight":[{"__symbolic":"property","decorators":[{"__symbolic":"call","expression":{"__symbolic":"reference","module":"@angular/core","name":"Input"}}]}],"childWidth":[{"__symbolic":"property","decorators":[{"__symbolic":"call","expression":{"__symbolic":"reference","module":"@angular/core","name":"Input"}}]}],"childHeight":[{"__symbolic":"property","decorators":[{"__symbolic":"call","expression":{"__symbolic":"reference","module":"@angular/core","name":"Input"}}]}],"update":[{"__symbolic":"property","decorators":[{"__symbolic":"call","expression":{"__symbolic":"reference","module":"@angular/core","name":"Output"}}]}],"change":[{"__symbolic":"property","decorators":[{"__symbolic":"call","expression":{"__symbolic":"reference","module":"@angular/core","name":"Output"}}]}],"start":[{"__symbolic":"property","decorators":[{"__symbolic":"call","expression":{"__symbolic":"reference","module":"@angular/core","name":"Output"}}]}],"end":[{"__symbolic":"property","decorators":[{"__symbolic":"call","expression":{"__symbolic":"reference","module":"@angular/core","name":"Output"}}]}],"contentElementRef":[{"__symbolic":"property","decorators":[{"__symbolic":"call","expression":{"__symbolic":"reference","module":"@angular/core","name":"ViewChild"},"arguments":["content",{"read":{"__symbolic":"reference","module":"@angular/core","name":"ElementRef"}}]}]}],"__ctor__":[{"__symbolic":"constructor","parameters":[{"__symbolic":"reference","module":"@angular/core","name":"ElementRef"},{"__symbolic":"reference","module":"@angular/core","name":"Renderer"}]}],"onScroll":[{"__symbolic":"method","decorators":[{"__symbolic":"call","expression":{"__symbolic":"reference","module":"@angular/core","name":"HostListener"},"arguments":["scroll"]}]}],"ngOnInit":[{"__symbolic":"method"}],"ngOnChanges":[{"__symbolic":"method"}],"ngOnDestroy":[{"__symbolic":"method"}],"refresh":[{"__symbolic":"method"}],"scrollInto":[{"__symbolic":"method"}],"countItemsPerRow":[{"__symbolic":"method"}],"calculateDimensions":[{"__symbolic":"method"}],"calculateItems":[{"__symbolic":"method"}]}},"VirtualScrollModule":{"__symbolic":"class","decorators":[{"__symbolic":"call","expression":{"__symbolic":"reference","module":"@angular/core","name":"NgModule"},"arguments":[{"imports":[{"__symbolic":"reference","module":"@angular/common","name":"CommonModule"}],"exports":[{"__symbolic":"reference","name":"VirtualScrollComponent"}],"declarations":[{"__symbolic":"reference","name":"VirtualScrollComponent"}]}]}]}}}] |
{ | ||
"name": "angular2-virtual-scroll", | ||
"version": "0.1.5", | ||
"version": "0.1.6", | ||
"description": "Angular 2 module for virtual -infinite- list. Supports multi-column", | ||
@@ -5,0 +5,0 @@ "main": "dist/virtual-scroll.js", |
@@ -22,3 +22,3 @@ | ||
``` | ||
```html | ||
<virtual-scroll [items]="items" (update)="viewPortItems = $event"> | ||
@@ -32,2 +32,13 @@ | ||
alternatively | ||
```html | ||
<div virtualScroll [items]="items" (update)="viewPortItems = $event"> | ||
<list-item *ngFor="let item of viewPortItems" [item]="item"> | ||
</list-item> | ||
</div> | ||
``` | ||
## Get Started | ||
@@ -37,3 +48,3 @@ | ||
``` | ||
```sh | ||
npm install angular2-virtual-scroll --save | ||
@@ -44,3 +55,3 @@ ``` | ||
``` | ||
```ts | ||
.... | ||
@@ -64,3 +75,3 @@ import { VirtualScrollModule } from 'angular2-virtual-scroll'; | ||
``` | ||
```ts | ||
<virtual-scroll [items]="items" (update)="viewPortItems = $event"> | ||
@@ -78,3 +89,3 @@ | ||
``` | ||
```ts | ||
import { Component, Input } from '@angular/core'; | ||
@@ -115,3 +126,3 @@ | ||
``` | ||
```html | ||
<virtual-scroll [items]="items" (update)="viewPortItems = $event"> | ||
@@ -136,3 +147,3 @@ <div *ngFor="let item of viewPortItems">{{item?.name}}</div> | ||
``` | ||
```html | ||
<virtual-scroll [items]="items" | ||
@@ -153,3 +164,3 @@ [childWidth]="80" | ||
``` | ||
```ts | ||
@@ -200,3 +211,3 @@ import { ChangeEvent } from '@angular2-virtual-scroll'; | ||
``` | ||
```ts | ||
import { Component, ViewChild } from '@angular/core'; | ||
@@ -227,2 +238,12 @@ import { VirtualScrollComponent } from 'angular2-virtual-scroll'; | ||
## Sorting Items | ||
Always be sure to send an immutable copy of items to virtual scroll to avoid unintended behavior. You need to be careful when doing non-immutable operations such as sorting: | ||
```ts | ||
sort() { | ||
this.items = [].concat(this.items || []).sort() | ||
} | ||
``` | ||
This will be deprecated once [Resize Observer](https://wicg.github.io/ResizeObserver/) is fully implemented. | ||
@@ -229,0 +250,0 @@ |
Sorry, the diff of this file is not supported yet
License Policy Violation
LicenseThis package is not allowed per your license policy. Review the package's license to ensure compliance.
Found 1 instance in 1 package
License Policy Violation
LicenseThis package is not allowed per your license policy. Review the package's license to ensure compliance.
Found 1 instance in 1 package
40984
269
283