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.
@@ -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, debounceTime, switchMap, of } from 'rxjs';
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, scrollDirection: undefined, ...options };
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, scrollDirection: undefined, ...options };
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 { scrollDirection = 0, fromItemId, bounds, collection, dynamicSize, isVertical, itemSize, itemsOffset, scrollSize, snap, stickyMap } = options;
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, totalSize = dynamicSize ? this.getBoundsFromCache(collection, typicalItemSize, isVertical) : totalLength * typicalItemSize, snippedPos = Math.floor(scrollSize), leftItemsWeights = [], isFromId = fromItemId !== undefined && (typeof fromItemId === 'number' && fromItemId > -1)
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, fullHeight = 0, startIndex;
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
- if (!stickyMap[fromItemId]) {
554
- leftHiddenItemsWeight += stickyComponentSize;
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
- fullHeight = totalLength * typicalItemSize;
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 = fullHeight - this._previouseFullHeigh;
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
- if (scrollDirection !== 0) {
654
- this._previouseFullHeigh = fullHeight;
655
- }
720
+ this._previouseFullHeigh = totalSize;
656
721
  return metrics;
657
722
  }
658
- clearDelta() {
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._scrollDirection = previouseScrollSize > scrollSize ? -1 : 1;
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, fireEvent = true) => {
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
- if (fireEvent) {
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, $scrolledItemId = this._$scrolledItemId.asObservable();
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, $scrolledItemId, $bounds, $items, $stickyMap, $scrollSize, $itemSize,
1171
+ combineLatest([this.$initialized, $bounds, $items, $stickyMap, $scrollSize, $itemSize,
1109
1172
  $itemsOffset, $snap, $isVertical, $dynamicSize, $cacheVersion,
1110
- ]).pipe(takeUntilDestroyed(), distinctUntilChanged(), debounceTime(0), filter(([initialized]) => !!initialized), switchMap(([, scrolledItemId, bounds, items, stickyMap, scrollSize, itemSize, itemsOffset, snap, isVertical, dynamicSize, cacheVersion,]) => {
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, fromItemId: scrolledItemId,
1178
+ itemsOffset, scrollSize: scrollSize, snap,
1116
1179
  };
1117
- if (dynamicSize && scrolledItemId !== undefined) {
1118
- const scrollSize = this._trackBox.getItemPosition(scrolledItemId, stickyMap, { ...opts, scrollSize: actualScrollSize });
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: this._isVertical ? container.nativeElement.scrollTop : container.nativeElement.scrollLeft,
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 = { [this._isVertical ? TOP_PROP_NAME : LEFT_PROP_NAME]: scrollSize, behavior };
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
- clearTimeout(this._scrollToTimeout);
1233
- this._scrollToTimeout = setTimeout(() => {
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
- }, 100);
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
- if (this._scrollToTimeout) {
1268
- clearTimeout(this._scrollToTimeout);
1269
- }
1337
+ this.clearScrollToRepeatExecutionTimeout();
1270
1338
  if (this._trackBox) {
1271
1339
  this._trackBox.dispose();
1272
1340
  }