diff --git a/src/components/virtual-scroll/test/basic/app.module.ts b/src/components/virtual-scroll/test/basic/app.module.ts index 70ddf47daef..9faa4cbee5e 100644 --- a/src/components/virtual-scroll/test/basic/app.module.ts +++ b/src/components/virtual-scroll/test/basic/app.module.ts @@ -11,19 +11,7 @@ export class E2EPage { webview: string = ''; counter: number = 0; - constructor(plt: Platform, public navCtrl: NavController) { - if (plt.is('ios')) { - if (plt.testUserAgent('Safari')) { - this.webview = ': iOS Safari'; - - } else if (!!(window as any)['webkit']) { - this.webview = ': iOS WKWebView'; - - } else { - this.webview = ': iOS UIWebView'; - } - } - } + constructor(plt: Platform, public navCtrl: NavController) {} addItems() { if (this.items.length === 0) { @@ -54,8 +42,21 @@ export class E2EPage { this.counter++; } - reload() { - window.location.reload(true); + addRandomItem() { + const index = Math.floor(Math.random() * this.items.length); + console.log('Adding to index: ', index); + this.items.splice( index, 0, { + value: Math.floor(Math.random() * 10000), + someMethod: function() { + return '!!'; + } + }); + } + + changeItem() { + const index = Math.floor(Math.random() * this.items.length); + console.log('Change to index: ', index); + this.items[index] = { value: Math.floor(Math.random() * 10000), someMethod: () => '!!' }; } trackByFn(index: number, item: any) { diff --git a/src/components/virtual-scroll/test/basic/main.html b/src/components/virtual-scroll/test/basic/main.html index 352d64427ac..fd3b89a4e85 100644 --- a/src/components/virtual-scroll/test/basic/main.html +++ b/src/components/virtual-scroll/test/basic/main.html @@ -1,12 +1,14 @@ - Virtual Scroll{{webview}} - + diff --git a/src/components/virtual-scroll/virtual-scroll.ts b/src/components/virtual-scroll/virtual-scroll.ts index af1dabf85dc..18829b5e54b 100644 --- a/src/components/virtual-scroll/virtual-scroll.ts +++ b/src/components/virtual-scroll/virtual-scroll.ts @@ -233,7 +233,8 @@ export class VirtualScroll implements DoCheck, AfterContentInit, OnDestroy { scrollTop: 0, }; _queue: number = SCROLL_QUEUE_NO_CHANGES; - _recordSize: number = 0; + + _virtualTrackBy: TrackByFn; @ContentChild(VirtualItem) _itmTmp: VirtualItem; @@ -379,7 +380,6 @@ export class VirtualScroll implements DoCheck, AfterContentInit, OnDestroy { return this._virtualTrackBy; } - constructor( private _iterableDiffers: IterableDiffers, private _elementRef: ElementRef, @@ -412,6 +412,22 @@ export class VirtualScroll implements DoCheck, AfterContentInit, OnDestroy { }); } + /** + * @hidden + */ + firstRecord(): number { + const cells = this._cells; + return (cells.length > 0) ? cells[0].record : 0; + } + + /** + * @hidden + */ + lastRecord(): number { + const cells = this._cells; + return (cells.length > 0) ? cells[cells.length - 1].record : 0; + } + /** * @hidden */ @@ -429,24 +445,38 @@ export class VirtualScroll implements DoCheck, AfterContentInit, OnDestroy { let needClean = false; if (changes) { - changes.forEachOperation((item, _, cindex) => { - if (item.previousIndex != null || (cindex < this._recordSize)) { + var lastRecord = this.lastRecord() + 1; + + changes.forEachOperation((_, pindex, cindex) => { + + // add new record after current position + if (pindex === null && (cindex < lastRecord)) { + console.debug('adding record before current position, slow path'); + needClean = true; + return; + } + // remove record after current position + if (pindex < lastRecord && cindex === null) { + console.debug('removing record before current position, slow path'); needClean = true; + return; } }); } else { needClean = true; } - this._recordSize = this._records.length; this.readUpdate(needClean); this.writeUpdate(needClean); } + /** + * @hidden + */ readUpdate(needClean: boolean) { if (needClean) { // reset everything - console.debug(`virtual-scroll, readUpdate: slow path`); + console.debug('virtual-scroll, readUpdate: slow path'); this._cells.length = 0; this._nodes.length = 0; this._itmTmp.viewContainer.clear(); @@ -458,8 +488,11 @@ export class VirtualScroll implements DoCheck, AfterContentInit, OnDestroy { } } + /** + * @hidden + */ writeUpdate(needClean: boolean) { - console.debug(`virtual-scroll, writeUpdate`); + console.debug('virtual-scroll, writeUpdate need clean:', needClean); const data = this._data; const stopAtHeight = (data.scrollTop + data.renderHeight); data.scrollDiff = SCROLL_DIFFERENCE_MINIMUM + 1; @@ -475,6 +508,9 @@ export class VirtualScroll implements DoCheck, AfterContentInit, OnDestroy { this.renderVirtual(needClean); } + /** + * @hidden + */ private calcDimensions() { calcDimensions(this._data, this._elementRef.nativeElement, this.approxItemWidth, this.approxItemHeight, @@ -524,7 +560,7 @@ export class VirtualScroll implements DoCheck, AfterContentInit, OnDestroy { this._itmTmp.viewContainer, this._itmTmp.templateRef, this._hdrTmp && this._hdrTmp.templateRef, - this._ftrTmp && this._ftrTmp.templateRef, needClean, + this._ftrTmp && this._ftrTmp.templateRef, needClean ); }); @@ -571,7 +607,7 @@ export class VirtualScroll implements DoCheck, AfterContentInit, OnDestroy { } /** - * @private + * @hidden */ resize() { // only continue if we've already initialized @@ -605,7 +641,7 @@ export class VirtualScroll implements DoCheck, AfterContentInit, OnDestroy { } /** - * @private + * @hidden */ private _stepChangeDetection() { // we need to do some change detection in this frame @@ -624,7 +660,7 @@ export class VirtualScroll implements DoCheck, AfterContentInit, OnDestroy { } /** - * @private + * @hidden */ private _stepNoChanges() { const data = this._data; @@ -675,7 +711,7 @@ export class VirtualScroll implements DoCheck, AfterContentInit, OnDestroy { } /** - * @private + * @hidden */ scrollUpdate(ev: ScrollEvent) { // set the scroll top from the scroll event @@ -718,6 +754,7 @@ export class VirtualScroll implements DoCheck, AfterContentInit, OnDestroy { } /** + * @hidden * NO DOM */ private _listeners() { @@ -738,6 +775,7 @@ export class VirtualScroll implements DoCheck, AfterContentInit, OnDestroy { } /** + * @hidden * DOM WRITE */ private _setHeight(newVirtualHeight: number) { @@ -762,6 +800,9 @@ export class VirtualScroll implements DoCheck, AfterContentInit, OnDestroy { } } + /** + * @hidden + */ setElementClass(className: string, add: boolean) { this._renderer.setElementClass(this._elementRef.nativeElement, className, add); }