ng-virtual-list 16.0.3 → 16.0.4
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +2 -2
- package/esm2022/lib/const/index.mjs +2 -1
- package/esm2022/lib/models/index.mjs +1 -1
- package/esm2022/lib/models/scroll-direction.model.mjs +2 -0
- package/esm2022/lib/models/scroll-event.model.mjs +2 -0
- package/esm2022/lib/ng-virtual-list.component.mjs +44 -47
- package/esm2022/lib/utils/cacheMap.mjs +42 -1
- package/esm2022/lib/utils/trackBox.mjs +49 -19
- package/fesm2022/ng-virtual-list.mjs +131 -63
- package/fesm2022/ng-virtual-list.mjs.map +1 -1
- package/lib/const/index.d.ts +1 -0
- package/lib/models/index.d.ts +3 -1
- package/lib/models/scroll-direction.model.d.ts +5 -0
- package/lib/models/scroll-event.model.d.ts +18 -0
- package/lib/ng-virtual-list.component.d.ts +6 -9
- package/lib/utils/cacheMap.d.ts +10 -0
- package/lib/utils/trackBox.d.ts +3 -3
- package/package.json +1 -1
|
@@ -3,7 +3,7 @@ import { Component, ChangeDetectionStrategy, EventEmitter as EventEmitter$1, Vie
|
|
|
3
3
|
import * as i1 from '@angular/common';
|
|
4
4
|
import { CommonModule } from '@angular/common';
|
|
5
5
|
import { takeUntilDestroyed } from '@angular/core/rxjs-interop';
|
|
6
|
-
import { BehaviorSubject, filter, map, tap, combineLatest, distinctUntilChanged,
|
|
6
|
+
import { BehaviorSubject, filter, map, tap, combineLatest, distinctUntilChanged, switchMap, of } from 'rxjs';
|
|
7
7
|
|
|
8
8
|
/**
|
|
9
9
|
* Axis of the arrangement of virtual list elements.
|
|
@@ -32,6 +32,7 @@ const DEFAULT_DYNAMIC_SIZE = false;
|
|
|
32
32
|
const TRACK_BY_PROPERTY_NAME = 'id';
|
|
33
33
|
const DEFAULT_DIRECTION = Directions.VERTICAL;
|
|
34
34
|
const DISPLAY_OBJECTS_LENGTH_MESUREMENT_ERROR = 1;
|
|
35
|
+
const MAX_SCROLL_TO_ITERATIONS = 5;
|
|
35
36
|
// presets
|
|
36
37
|
const BEHAVIOR_AUTO = 'auto';
|
|
37
38
|
const BEHAVIOR_INSTANT = 'instant';
|
|
@@ -411,6 +412,7 @@ class EventEmitter {
|
|
|
411
412
|
}
|
|
412
413
|
}
|
|
413
414
|
|
|
415
|
+
const MAX_SCROLL_DIRECTION_POOL = 10, CLEAR_SCROLL_DIRECTION_TO = 0;
|
|
414
416
|
/**
|
|
415
417
|
* Cache map.
|
|
416
418
|
* Emits a change event on each mutation.
|
|
@@ -426,12 +428,51 @@ class CacheMap extends EventEmitter {
|
|
|
426
428
|
get delta() {
|
|
427
429
|
return this._delta;
|
|
428
430
|
}
|
|
431
|
+
_deltaDirection = 1;
|
|
432
|
+
set deltaDirection(v) {
|
|
433
|
+
this._deltaDirection = v;
|
|
434
|
+
this._scrollDirection = this.calcScrollDirection(v);
|
|
435
|
+
}
|
|
436
|
+
get deltaDirection() {
|
|
437
|
+
return this._deltaDirection;
|
|
438
|
+
}
|
|
439
|
+
_scrollDirectionCache = [];
|
|
440
|
+
_scrollDirection = 1;
|
|
441
|
+
get scrollDirection() {
|
|
442
|
+
return this._scrollDirection;
|
|
443
|
+
}
|
|
429
444
|
get version() {
|
|
430
445
|
return this._version;
|
|
431
446
|
}
|
|
447
|
+
_clearScrollDirectionDebounce = debounce(() => {
|
|
448
|
+
while (this._scrollDirectionCache.length > CLEAR_SCROLL_DIRECTION_TO) {
|
|
449
|
+
this._scrollDirectionCache.shift();
|
|
450
|
+
}
|
|
451
|
+
}, 10);
|
|
432
452
|
constructor() {
|
|
433
453
|
super();
|
|
434
454
|
}
|
|
455
|
+
clearScrollDirectionCache() {
|
|
456
|
+
this._clearScrollDirectionDebounce.execute();
|
|
457
|
+
}
|
|
458
|
+
calcScrollDirection(v) {
|
|
459
|
+
while (this._scrollDirectionCache.length >= MAX_SCROLL_DIRECTION_POOL) {
|
|
460
|
+
this._scrollDirectionCache.shift();
|
|
461
|
+
}
|
|
462
|
+
this._scrollDirectionCache.push(v);
|
|
463
|
+
const dict = { [-1]: 0, [0]: 0, [1]: 0 };
|
|
464
|
+
for (let i = 0, l = this._scrollDirectionCache.length; i < l; i++) {
|
|
465
|
+
const dir = this._scrollDirectionCache[i];
|
|
466
|
+
dict[dir] += 1;
|
|
467
|
+
}
|
|
468
|
+
if (dict[-1] > dict[1]) {
|
|
469
|
+
return -1;
|
|
470
|
+
}
|
|
471
|
+
else if (dict[1] > dict[-1]) {
|
|
472
|
+
return 1;
|
|
473
|
+
}
|
|
474
|
+
return -1;
|
|
475
|
+
}
|
|
435
476
|
bumpVersion() {
|
|
436
477
|
this._version = this._version === Number.MAX_SAFE_INTEGER ? 0 : this._version + 1;
|
|
437
478
|
}
|
|
@@ -506,12 +547,12 @@ class TrackBox extends CacheMap {
|
|
|
506
547
|
this._debounceChanges.execute(this._version);
|
|
507
548
|
}
|
|
508
549
|
getItemPosition(id, stickyMap, options) {
|
|
509
|
-
const opt = { fromItemId: id, stickyMap,
|
|
550
|
+
const opt = { fromItemId: id, stickyMap, ...options };
|
|
510
551
|
const { scrollSize } = this.recalculateMetrics(opt);
|
|
511
552
|
return scrollSize;
|
|
512
553
|
}
|
|
513
554
|
updateCollection(items, stickyMap, options) {
|
|
514
|
-
const opt = { stickyMap,
|
|
555
|
+
const opt = { stickyMap, ...options };
|
|
515
556
|
this.cacheElements();
|
|
516
557
|
const metrics = this.recalculateMetrics({
|
|
517
558
|
...opt,
|
|
@@ -520,14 +561,35 @@ class TrackBox extends CacheMap {
|
|
|
520
561
|
const displayItems = this.generateDisplayCollection(items, stickyMap, metrics);
|
|
521
562
|
return { displayItems, totalSize: metrics.totalSize, delta: metrics.delta };
|
|
522
563
|
}
|
|
564
|
+
getElementNumToEnd(i, collection, map, typicalItemSize, size, isVertical) {
|
|
565
|
+
const sizeProperty = isVertical ? HEIGHT_PROP_NAME : WIDTH_PROP_NAME;
|
|
566
|
+
let offset = 0, num = 0;
|
|
567
|
+
for (let j = collection.length - 1; j >= i; j--) {
|
|
568
|
+
const item = collection[j];
|
|
569
|
+
let itemSize = 0;
|
|
570
|
+
if (map.has(item.id)) {
|
|
571
|
+
const bounds = map.get(item.id);
|
|
572
|
+
itemSize = bounds ? bounds[sizeProperty] : typicalItemSize;
|
|
573
|
+
}
|
|
574
|
+
else {
|
|
575
|
+
itemSize = typicalItemSize;
|
|
576
|
+
}
|
|
577
|
+
offset += itemSize;
|
|
578
|
+
num++;
|
|
579
|
+
if (offset > size) {
|
|
580
|
+
return { num: 0, offset };
|
|
581
|
+
}
|
|
582
|
+
}
|
|
583
|
+
return { num, offset };
|
|
584
|
+
}
|
|
523
585
|
/**
|
|
524
586
|
* Calculates list metrics
|
|
525
587
|
*/
|
|
526
588
|
recalculateMetrics(options) {
|
|
527
|
-
const {
|
|
528
|
-
const { width, height } = bounds, sizeProperty = isVertical ? HEIGHT_PROP_NAME : WIDTH_PROP_NAME, size = isVertical ? height : width, totalLength = collection.length, typicalItemSize = itemSize, w = isVertical ? width : typicalItemSize, h = isVertical ? typicalItemSize : height,
|
|
589
|
+
const { fromItemId, bounds, collection, dynamicSize, isVertical, itemSize, itemsOffset, scrollSize, snap, stickyMap } = options;
|
|
590
|
+
const { width, height } = bounds, sizeProperty = isVertical ? HEIGHT_PROP_NAME : WIDTH_PROP_NAME, size = isVertical ? height : width, totalLength = collection.length, typicalItemSize = itemSize, w = isVertical ? width : typicalItemSize, h = isVertical ? typicalItemSize : height, snippedPos = Math.floor(scrollSize), leftItemsWeights = [], isFromId = fromItemId !== undefined && (typeof fromItemId === 'number' && fromItemId > -1)
|
|
529
591
|
|| (typeof fromItemId === 'string' && fromItemId > '-1');
|
|
530
|
-
let itemsFromStartToScrollEnd = -1, itemsFromDisplayEndToOffsetEnd = 0, itemsFromStartToDisplayEnd = -1, leftItemLength = 0, rightItemLength = 0, leftItemsWeight = 0, rightItemsWeight = 0, leftHiddenItemsWeight = 0, totalItemsToDisplayEndWeight = 0, itemById = undefined, itemByIdPos = 0, lastDisplayItemId = undefined, actualScrollSize = itemByIdPos,
|
|
592
|
+
let itemsFromStartToScrollEnd = -1, itemsFromDisplayEndToOffsetEnd = 0, itemsFromStartToDisplayEnd = -1, leftItemLength = 0, rightItemLength = 0, leftItemsWeight = 0, rightItemsWeight = 0, leftHiddenItemsWeight = 0, totalItemsToDisplayEndWeight = 0, itemById = undefined, itemByIdPos = 0, lastDisplayItemId = undefined, actualScrollSize = itemByIdPos, totalSize = 0, startIndex;
|
|
531
593
|
if (dynamicSize) {
|
|
532
594
|
let y = 0, stickyCollectionItem = undefined, stickyComponentSize = 0;
|
|
533
595
|
for (let i = 0, l = collection.length; i < l; i++) {
|
|
@@ -540,6 +602,7 @@ class TrackBox extends CacheMap {
|
|
|
540
602
|
else {
|
|
541
603
|
componentSize = typicalItemSize;
|
|
542
604
|
}
|
|
605
|
+
totalSize += componentSize;
|
|
543
606
|
if (isFromId) {
|
|
544
607
|
if (itemById === undefined) {
|
|
545
608
|
if (stickyMap && stickyMap[collectionItem.id] > 0) {
|
|
@@ -547,13 +610,18 @@ class TrackBox extends CacheMap {
|
|
|
547
610
|
stickyCollectionItem = collectionItem;
|
|
548
611
|
}
|
|
549
612
|
if (collectionItem.id === fromItemId) {
|
|
550
|
-
itemById = collectionItem;
|
|
551
|
-
itemByIdPos = y;
|
|
552
613
|
if (stickyCollectionItem && stickyMap && stickyMap[stickyCollectionItem.id] > 0) {
|
|
553
|
-
|
|
554
|
-
|
|
614
|
+
const { num } = this.getElementNumToEnd(i, collection, map, typicalItemSize, size, isVertical);
|
|
615
|
+
if (num > 0) {
|
|
616
|
+
y -= size - componentSize;
|
|
617
|
+
}
|
|
618
|
+
else {
|
|
619
|
+
y -= stickyComponentSize;
|
|
620
|
+
leftHiddenItemsWeight -= stickyComponentSize;
|
|
555
621
|
}
|
|
556
622
|
}
|
|
623
|
+
itemById = collectionItem;
|
|
624
|
+
itemByIdPos = y;
|
|
557
625
|
}
|
|
558
626
|
else {
|
|
559
627
|
leftItemsWeights.push(componentSize);
|
|
@@ -586,7 +654,6 @@ class TrackBox extends CacheMap {
|
|
|
586
654
|
}
|
|
587
655
|
y += componentSize;
|
|
588
656
|
}
|
|
589
|
-
fullHeight = y;
|
|
590
657
|
if (itemsFromStartToScrollEnd === -1) {
|
|
591
658
|
itemsFromStartToScrollEnd = 0;
|
|
592
659
|
}
|
|
@@ -612,12 +679,12 @@ class TrackBox extends CacheMap {
|
|
|
612
679
|
rightItemsWeight = rightItemLength * typicalItemSize,
|
|
613
680
|
leftHiddenItemsWeight = itemsFromStartToScrollEnd * typicalItemSize,
|
|
614
681
|
totalItemsToDisplayEndWeight = itemsFromStartToDisplayEnd * typicalItemSize;
|
|
615
|
-
actualScrollSize = scrollSize
|
|
616
|
-
|
|
682
|
+
actualScrollSize = scrollSize;
|
|
683
|
+
totalSize = totalLength * typicalItemSize;
|
|
617
684
|
}
|
|
618
685
|
startIndex = Math.min(itemsFromStartToScrollEnd - leftItemLength, totalLength > 0 ? totalLength - 1 : 0);
|
|
619
|
-
const itemsOnDisplay = totalItemsToDisplayEndWeight - leftHiddenItemsWeight, itemsOnDisplayLength = itemsFromStartToDisplayEnd - itemsFromStartToScrollEnd, startPosition = leftHiddenItemsWeight - leftItemsWeight, renderItems = itemsOnDisplayLength + leftItemLength + rightItemLength, delta =
|
|
620
|
-
if (scrollDirection === -1) {
|
|
686
|
+
const itemsOnDisplay = totalItemsToDisplayEndWeight - leftHiddenItemsWeight, itemsOnDisplayLength = itemsFromStartToDisplayEnd - itemsFromStartToScrollEnd, startPosition = leftHiddenItemsWeight - leftItemsWeight, renderItems = itemsOnDisplayLength + leftItemLength + rightItemLength, delta = totalSize - this._previouseFullHeigh;
|
|
687
|
+
if (this.scrollDirection === -1) {
|
|
621
688
|
this._delta += delta;
|
|
622
689
|
}
|
|
623
690
|
const metrics = {
|
|
@@ -650,13 +717,17 @@ class TrackBox extends CacheMap {
|
|
|
650
717
|
totalSize,
|
|
651
718
|
typicalItemSize,
|
|
652
719
|
};
|
|
653
|
-
|
|
654
|
-
this._previouseFullHeigh = fullHeight;
|
|
655
|
-
}
|
|
720
|
+
this._previouseFullHeigh = totalSize;
|
|
656
721
|
return metrics;
|
|
657
722
|
}
|
|
658
|
-
|
|
723
|
+
clearDeltaDirection() {
|
|
724
|
+
this.clearScrollDirectionCache();
|
|
725
|
+
}
|
|
726
|
+
clearDelta(clearDirectionDetector = false) {
|
|
659
727
|
this._delta = 0;
|
|
728
|
+
if (clearDirectionDetector) {
|
|
729
|
+
this.clearScrollDirectionCache();
|
|
730
|
+
}
|
|
660
731
|
}
|
|
661
732
|
generateDisplayCollection(items, stickyMap, metrics) {
|
|
662
733
|
const {
|
|
@@ -980,27 +1051,20 @@ class NgVirtualListComponent {
|
|
|
980
1051
|
}
|
|
981
1052
|
;
|
|
982
1053
|
get itemsOffset() { return this._$itemsOffset.getValue(); }
|
|
983
|
-
_scrollToTimeout;
|
|
984
1054
|
_isVertical = this.getIsVertical();
|
|
985
1055
|
_displayComponents = [];
|
|
986
1056
|
_$bounds = new BehaviorSubject(null);
|
|
987
1057
|
_$scrollSize = new BehaviorSubject(0);
|
|
988
1058
|
_resizeObserver = null;
|
|
989
|
-
/**
|
|
990
|
-
* only dynamic
|
|
991
|
-
*/
|
|
992
|
-
_$scrolledItemId = new BehaviorSubject(undefined);
|
|
993
1059
|
_onResizeHandler = () => {
|
|
994
1060
|
this._$bounds.next(this._container?.nativeElement?.getBoundingClientRect() ?? null);
|
|
995
1061
|
};
|
|
996
|
-
_scrollDirection = 0;
|
|
997
1062
|
_onScrollHandler = (e) => {
|
|
998
|
-
this._$scrolledItemId.next(undefined);
|
|
999
1063
|
const container = this._container?.nativeElement;
|
|
1000
1064
|
if (container) {
|
|
1001
1065
|
const dynamicSize = this.dynamicSize, delta = this._trackBox.delta, scrollSize = (this._isVertical ? container.scrollTop : container.scrollLeft), previouseScrollSize = this._$scrollSize.getValue();
|
|
1002
1066
|
let actualScrollSize = scrollSize;
|
|
1003
|
-
this.
|
|
1067
|
+
this._trackBox.deltaDirection = previouseScrollSize > scrollSize ? -1 : 1;
|
|
1004
1068
|
if (dynamicSize && delta !== 0) {
|
|
1005
1069
|
actualScrollSize = scrollSize + delta;
|
|
1006
1070
|
const params = {
|
|
@@ -1014,7 +1078,7 @@ class NgVirtualListComponent {
|
|
|
1014
1078
|
}
|
|
1015
1079
|
}
|
|
1016
1080
|
this._$scrollSize.next(actualScrollSize);
|
|
1017
|
-
this.onScroll.emit(actualScrollSize);
|
|
1081
|
+
this.onScroll.emit({ scrollSize: actualScrollSize, direction: this._trackBox.scrollDirection });
|
|
1018
1082
|
}
|
|
1019
1083
|
};
|
|
1020
1084
|
scrollImmediately(container, params) {
|
|
@@ -1041,9 +1105,11 @@ class NgVirtualListComponent {
|
|
|
1041
1105
|
container.nativeElement.removeEventListener(SCROLL_END, this._scrollImmediatelyHandler);
|
|
1042
1106
|
}
|
|
1043
1107
|
}
|
|
1044
|
-
_onScrollEndHandler = (e
|
|
1108
|
+
_onScrollEndHandler = (e) => {
|
|
1045
1109
|
const container = this._container;
|
|
1046
1110
|
if (container) {
|
|
1111
|
+
this._trackBox.clearDelta();
|
|
1112
|
+
this._trackBox.clearDeltaDirection();
|
|
1047
1113
|
const itemSize = this.itemSize, snapToItem = this.snapToItem, dynamicSize = this.dynamicSize, delta = this._trackBox.delta, scrollSize = (this._isVertical ? container.nativeElement.scrollTop : container.nativeElement.scrollLeft);
|
|
1048
1114
|
let actualScrollSize = scrollSize;
|
|
1049
1115
|
if (dynamicSize && delta !== 0) {
|
|
@@ -1053,7 +1119,6 @@ class NgVirtualListComponent {
|
|
|
1053
1119
|
[this._isVertical ? TOP_PROP_NAME : LEFT_PROP_NAME]: actualScrollSize,
|
|
1054
1120
|
behavior: BEHAVIOR_INSTANT
|
|
1055
1121
|
};
|
|
1056
|
-
this._trackBox.clearDelta();
|
|
1057
1122
|
this._$scrollSize.next(actualScrollSize);
|
|
1058
1123
|
container.nativeElement.scroll(params);
|
|
1059
1124
|
return;
|
|
@@ -1071,9 +1136,7 @@ class NgVirtualListComponent {
|
|
|
1071
1136
|
}
|
|
1072
1137
|
}
|
|
1073
1138
|
this._$scrollSize.next(actualScrollSize);
|
|
1074
|
-
|
|
1075
|
-
this.onScrollEnd.emit(actualScrollSize);
|
|
1076
|
-
}
|
|
1139
|
+
this.onScroll.emit({ scrollSize: actualScrollSize, direction: this._trackBox.scrollDirection });
|
|
1077
1140
|
}
|
|
1078
1141
|
};
|
|
1079
1142
|
_$initialized = new BehaviorSubject(false);
|
|
@@ -1096,7 +1159,7 @@ class NgVirtualListComponent {
|
|
|
1096
1159
|
this._$initialized = new BehaviorSubject(false);
|
|
1097
1160
|
this.$initialized = this._$initialized.asObservable();
|
|
1098
1161
|
this._trackBox.displayComponents = this._displayComponents;
|
|
1099
|
-
const $bounds = this._$bounds.asObservable().pipe(filter(b => !!b)), $items = this.$items.pipe(map(i => !i ? [] : i)), $scrollSize = this._$scrollSize.asObservable(), $itemSize = this.$itemSize.pipe(map(v => v <= 0 ? DEFAULT_ITEM_SIZE : v)), $itemsOffset = this.$itemsOffset.pipe(map(v => v < 0 ? DEFAULT_ITEMS_OFFSET : v)), $stickyMap = this.$stickyMap.pipe(map(v => !v ? {} : v)), $snap = this.$snap, $isVertical = this.$direction.pipe(map(v => this.getIsVertical(v || DEFAULT_DIRECTION))), $dynamicSize = this.$dynamicSize, $cacheVersion = this.$cacheVersion
|
|
1162
|
+
const $bounds = this._$bounds.asObservable().pipe(filter(b => !!b)), $items = this.$items.pipe(map(i => !i ? [] : i)), $scrollSize = this._$scrollSize.asObservable(), $itemSize = this.$itemSize.pipe(map(v => v <= 0 ? DEFAULT_ITEM_SIZE : v)), $itemsOffset = this.$itemsOffset.pipe(map(v => v < 0 ? DEFAULT_ITEMS_OFFSET : v)), $stickyMap = this.$stickyMap.pipe(map(v => !v ? {} : v)), $snap = this.$snap, $isVertical = this.$direction.pipe(map(v => this.getIsVertical(v || DEFAULT_DIRECTION))), $dynamicSize = this.$dynamicSize, $cacheVersion = this.$cacheVersion;
|
|
1100
1163
|
$isVertical.pipe(takeUntilDestroyed(), tap(v => {
|
|
1101
1164
|
this._isVertical = v;
|
|
1102
1165
|
const el = this._elementRef.nativeElement;
|
|
@@ -1105,33 +1168,21 @@ class NgVirtualListComponent {
|
|
|
1105
1168
|
$dynamicSize.pipe(takeUntilDestroyed(), tap(dynamicSize => {
|
|
1106
1169
|
this.listenCacheChangesIfNeed(dynamicSize);
|
|
1107
1170
|
})).subscribe();
|
|
1108
|
-
combineLatest([this.$initialized, $
|
|
1171
|
+
combineLatest([this.$initialized, $bounds, $items, $stickyMap, $scrollSize, $itemSize,
|
|
1109
1172
|
$itemsOffset, $snap, $isVertical, $dynamicSize, $cacheVersion,
|
|
1110
|
-
]).pipe(takeUntilDestroyed(), distinctUntilChanged(),
|
|
1173
|
+
]).pipe(takeUntilDestroyed(), distinctUntilChanged(), filter(([initialized]) => !!initialized), switchMap(([, bounds, items, stickyMap, scrollSize, itemSize, itemsOffset, snap, isVertical, dynamicSize, cacheVersion,]) => {
|
|
1111
1174
|
const { width, height } = bounds;
|
|
1112
1175
|
let actualScrollSize = scrollSize;
|
|
1113
1176
|
const opts = {
|
|
1114
1177
|
bounds: { width, height }, collection: items, dynamicSize, isVertical, itemSize,
|
|
1115
|
-
itemsOffset, scrollSize: scrollSize, snap,
|
|
1178
|
+
itemsOffset, scrollSize: scrollSize, snap,
|
|
1116
1179
|
};
|
|
1117
|
-
|
|
1118
|
-
|
|
1119
|
-
actualScrollSize = scrollSize;
|
|
1120
|
-
this._$scrollSize.next(actualScrollSize);
|
|
1121
|
-
}
|
|
1122
|
-
const scrollDirection = this._scrollDirection, { displayItems, totalSize } = this._trackBox.updateCollection(items, stickyMap, {
|
|
1123
|
-
...opts, scrollSize: actualScrollSize, scrollDirection
|
|
1180
|
+
const { displayItems, totalSize } = this._trackBox.updateCollection(items, stickyMap, {
|
|
1181
|
+
...opts, scrollSize: actualScrollSize,
|
|
1124
1182
|
});
|
|
1125
1183
|
this.resetBoundsSize(isVertical, totalSize);
|
|
1126
1184
|
this.createDisplayComponentsIfNeed(displayItems);
|
|
1127
1185
|
this.tracking();
|
|
1128
|
-
if (dynamicSize && scrolledItemId !== undefined) {
|
|
1129
|
-
const container = this._container;
|
|
1130
|
-
if (container) {
|
|
1131
|
-
const params = { [this._isVertical ? TOP_PROP_NAME : LEFT_PROP_NAME]: scrollSize, behavior: BEHAVIOR_AUTO };
|
|
1132
|
-
this.scrollImmediately(container, params);
|
|
1133
|
-
}
|
|
1134
|
-
}
|
|
1135
1186
|
return of(displayItems);
|
|
1136
1187
|
})).subscribe();
|
|
1137
1188
|
combineLatest([this.$initialized, this.$itemRenderer]).pipe(takeUntilDestroyed(), distinctUntilChanged(), filter(([initialized]) => !!initialized), tap(([, itemRenderer]) => {
|
|
@@ -1207,6 +1258,14 @@ class NgVirtualListComponent {
|
|
|
1207
1258
|
* Behavior accepts the values "auto", "instant" and "smooth".
|
|
1208
1259
|
*/
|
|
1209
1260
|
scrollTo(id, behavior = BEHAVIOR_AUTO) {
|
|
1261
|
+
this.scrollToExecutor(id, behavior);
|
|
1262
|
+
}
|
|
1263
|
+
_scrollToRepeatExecutionTimeout;
|
|
1264
|
+
clearScrollToRepeatExecutionTimeout() {
|
|
1265
|
+
clearTimeout(this._scrollToRepeatExecutionTimeout);
|
|
1266
|
+
}
|
|
1267
|
+
scrollToExecutor(id, behavior, iteration = 0) {
|
|
1268
|
+
this.clearScrollToRepeatExecutionTimeout();
|
|
1210
1269
|
const items = this.items;
|
|
1211
1270
|
if (!items || !items.length) {
|
|
1212
1271
|
return;
|
|
@@ -1218,24 +1277,35 @@ class NgVirtualListComponent {
|
|
|
1218
1277
|
container.nativeElement.removeEventListener(SCROLL, this._onScrollHandler);
|
|
1219
1278
|
container.nativeElement.removeEventListener(SCROLL_END, this._onScrollEndHandler);
|
|
1220
1279
|
}
|
|
1221
|
-
const { width, height } = this._$bounds.getValue() || { width: 0, height: 0 }, stickyMap = this.stickyMap, items = this.items, opts = {
|
|
1280
|
+
const { width, height } = this._$bounds.getValue() || { width: 0, height: 0 }, stickyMap = this.stickyMap, items = this.items, isVertical = this._isVertical, opts = {
|
|
1222
1281
|
bounds: { width, height }, collection: items, dynamicSize, isVertical: this._isVertical, itemSize,
|
|
1223
|
-
itemsOffset: this.itemsOffset, scrollSize:
|
|
1282
|
+
itemsOffset: this.itemsOffset, scrollSize: isVertical ? container.nativeElement.scrollTop : container.nativeElement.scrollLeft,
|
|
1224
1283
|
snap: this.snap, fromItemId: id,
|
|
1225
|
-
}, scrollSize = this._trackBox.getItemPosition(id, stickyMap, opts), params = { [
|
|
1226
|
-
this._$scrolledItemId.next(id);
|
|
1284
|
+
}, scrollSize = this._trackBox.getItemPosition(id, stickyMap, opts), params = { [isVertical ? TOP_PROP_NAME : LEFT_PROP_NAME]: scrollSize, behavior };
|
|
1227
1285
|
this._$scrollSize.next(scrollSize);
|
|
1228
1286
|
if (container) {
|
|
1229
1287
|
const handler = () => {
|
|
1230
1288
|
if (container) {
|
|
1231
1289
|
container.nativeElement.removeEventListener(SCROLL_END, handler);
|
|
1232
|
-
|
|
1233
|
-
|
|
1290
|
+
const { displayItems, totalSize } = this._trackBox.updateCollection(items, stickyMap, {
|
|
1291
|
+
...opts, scrollSize, fromItemId: id,
|
|
1292
|
+
});
|
|
1293
|
+
this.resetBoundsSize(isVertical, totalSize);
|
|
1294
|
+
this.createDisplayComponentsIfNeed(displayItems);
|
|
1295
|
+
this.tracking();
|
|
1296
|
+
const _scrollSize = this._trackBox.getItemPosition(id, stickyMap, { ...opts, scrollSize, fromItemId: id });
|
|
1297
|
+
if (scrollSize < _scrollSize && iteration < MAX_SCROLL_TO_ITERATIONS) {
|
|
1298
|
+
this.clearScrollToRepeatExecutionTimeout();
|
|
1299
|
+
this._scrollToRepeatExecutionTimeout = setTimeout(() => {
|
|
1300
|
+
this.scrollToExecutor(id, BEHAVIOR_INSTANT, iteration + 1);
|
|
1301
|
+
});
|
|
1302
|
+
}
|
|
1303
|
+
else {
|
|
1304
|
+
this._$scrollSize.next(scrollSize);
|
|
1305
|
+
this.onScroll.emit({ scrollSize, direction: this._trackBox.scrollDirection });
|
|
1234
1306
|
container.nativeElement.addEventListener(SCROLL, this._onScrollHandler);
|
|
1235
1307
|
container.nativeElement.addEventListener(SCROLL_END, this._onScrollEndHandler);
|
|
1236
|
-
}
|
|
1237
|
-
this.listenCacheChangesIfNeed(dynamicSize);
|
|
1238
|
-
this.onScroll.emit(scrollSize);
|
|
1308
|
+
}
|
|
1239
1309
|
}
|
|
1240
1310
|
};
|
|
1241
1311
|
container.nativeElement.addEventListener(SCROLL_END, handler);
|
|
@@ -1264,9 +1334,7 @@ class NgVirtualListComponent {
|
|
|
1264
1334
|
}
|
|
1265
1335
|
}
|
|
1266
1336
|
ngOnDestroy() {
|
|
1267
|
-
|
|
1268
|
-
clearTimeout(this._scrollToTimeout);
|
|
1269
|
-
}
|
|
1337
|
+
this.clearScrollToRepeatExecutionTimeout();
|
|
1270
1338
|
if (this._trackBox) {
|
|
1271
1339
|
this._trackBox.dispose();
|
|
1272
1340
|
}
|