ng-virtual-list 19.7.20 → 19.7.22

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 CHANGED
@@ -115,7 +115,7 @@ items = Array.from({ length: 100000 }, (_, i) => ({ id: i, name: `Item #${i}` })
115
115
 
116
116
  Template:
117
117
  ```html
118
- <ng-virtual-list class="list" direction="horizontal" [items]="horizontalItems" [bufferSize]="50"
118
+ <ng-virtual-list class="list" direction="horizontal" [items]="horizontalItems" [bufferSize]="5" [maxBufferSize]="20"
119
119
  [itemRenderer]="horizontalItemRenderer" [itemSize]="64" [methodForSelecting]="'select'"
120
120
  [selectedIds]="2" (onSelect)="onSelect($event)" (onItemClick)="onItemClick($event)"></ng-virtual-list>
121
121
 
@@ -166,8 +166,8 @@ export class AppComponent {
166
166
  Template:
167
167
  ```html
168
168
  <ng-virtual-list class="list" direction="horizontal" [items]="horizontalGroupItems" [itemRenderer]="horizontalGroupItemRenderer"
169
- [bufferSize]="50" [itemConfigMap]="horizontalGroupItemConfigMap" [itemSize]="54" [snap]="true" [methodForSelecting]="'multi-select'"
170
- [selectedIds]="[3,2]" (onSelect)="onSelect($event)" (onItemClick)="onItemClick($event)"></ng-virtual-list>
169
+ [bufferSize]="5" [maxBufferSize]="20" [itemConfigMap]="horizontalGroupItemConfigMap" [itemSize]="54" [snap]="true"
170
+ methodForSelecting="multi-select" [selectedIds]="[3,2]" (onSelect)="onSelect($event)" (onItemClick)="onItemClick($event)"></ng-virtual-list>
171
171
 
172
172
  <ng-template #horizontalGroupItemRenderer let-data="data" let-config="config">
173
173
  @if (data) {
@@ -239,7 +239,7 @@ export class AppComponent {
239
239
 
240
240
  Template:
241
241
  ```html
242
- <ng-virtual-list class="list simple" [items]="items" [bufferSize]="50" [itemRenderer]="itemRenderer"
242
+ <ng-virtual-list class="list simple" [items]="items" [bufferSize]="5" [maxBufferSize]="20" [itemRenderer]="itemRenderer"
243
243
  [itemSize]="40"></ng-virtual-list>
244
244
 
245
245
  <ng-template #itemRenderer let-data="data">
@@ -280,7 +280,7 @@ export class AppComponent {
280
280
 
281
281
  Template:
282
282
  ```html
283
- <ng-virtual-list class="list simple" [items]="groupItems" [bufferSize]="50" [itemRenderer]="groupItemRenderer"
283
+ <ng-virtual-list class="list simple" [items]="groupItems" [bufferSize]="5" [maxBufferSize]="20" [itemRenderer]="groupItemRenderer"
284
284
  [itemConfigMap]="groupItemConfigMap" [itemSize]="40" [snap]="false"></ng-virtual-list>
285
285
 
286
286
  <ng-template #groupItemRenderer let-data="data">
@@ -307,7 +307,7 @@ Template:
307
307
 
308
308
  Template (with snapping):
309
309
  ```html
310
- <ng-virtual-list class="list simple" [items]="groupItems" [bufferSize]="50" [itemRenderer]="groupItemRenderer"
310
+ <ng-virtual-list class="list simple" [items]="groupItems" [bufferSize]="5" [maxBufferSize]="20" [itemRenderer]="groupItemRenderer"
311
311
  [itemConfigMap]="groupItemConfigMap" [itemSize]="40" [snap]="true"></ng-virtual-list>
312
312
 
313
313
  <ng-template #groupItemRenderer let-data="data">
@@ -372,7 +372,7 @@ Template
372
372
  <button class="scroll-to__button" (click)="onButtonScrollToIdClickHandler($event)">Scroll</button>
373
373
  </div>
374
374
 
375
- <ng-virtual-list #virtualList class="list" [items]="items" [itemRenderer]="itemRenderer" [bufferSize]="50"
375
+ <ng-virtual-list #virtualList class="list" [items]="items" [itemRenderer]="itemRenderer" [bufferSize]="5" [maxBufferSize]="20"
376
376
  [itemSize]="40"></ng-virtual-list>
377
377
 
378
378
  <ng-template #itemRenderer let-data="data">
@@ -426,7 +426,7 @@ Virtual list with height-adjustable elements.
426
426
 
427
427
  Template
428
428
  ```html
429
- <ng-virtual-list #dynamicList class="list" [items]="groupDynamicItems" [itemRenderer]="groupItemRenderer" [bufferSize]="10"
429
+ <ng-virtual-list #dynamicList class="list" [items]="groupDynamicItems" [itemRenderer]="groupItemRenderer" [bufferSize]="5" [maxBufferSize]="20"
430
430
  [itemConfigMap]="groupDynamicItemConfigMap" [dynamicSize]="true" [snap]="true"></ng-virtual-list>
431
431
 
432
432
  <ng-template #groupItemRenderer let-data="data">
@@ -565,7 +565,7 @@ List items are encapsulated in shadowDOM, so to override default styles you need
565
565
  Selecting even elements:
566
566
 
567
567
  ```html
568
- <ng-virtual-list class="list" direction="horizontal" [items]="horizontalItems" [bufferSize]="5"
568
+ <ng-virtual-list class="list" direction="horizontal" [items]="horizontalItems" [bufferSize]="5" [maxBufferSize]="20"
569
569
  [itemRenderer]="horizontalItemRenderer" [itemSize]="54"></ng-virtual-list>
570
570
 
571
571
  <ng-template #horizontalItemRenderer let-data="data" let-config="config">
@@ -2,7 +2,7 @@ import * as i1 from '@angular/common';
2
2
  import { CommonModule } from '@angular/common';
3
3
  import * as i0 from '@angular/core';
4
4
  import { Injectable, inject, signal, ElementRef, ChangeDetectionStrategy, Component, viewChild, output, input, ViewContainerRef, ViewChild, ViewEncapsulation } from '@angular/core';
5
- import { Subject, tap, fromEvent, combineLatest, map, filter, distinctUntilChanged, skip, switchMap, of } from 'rxjs';
5
+ import { Subject, tap, fromEvent, combineLatest, map, filter, distinctUntilChanged, switchMap, of } from 'rxjs';
6
6
  import { BehaviorSubject } from 'rxjs/internal/BehaviorSubject';
7
7
  import { takeUntilDestroyed, toObservable } from '@angular/core/rxjs-interop';
8
8
 
@@ -1259,7 +1259,11 @@ const bufferInterpolation = (currentBufferValue, array, value, extra) => {
1259
1259
  return Math.ceil(buffer / l);
1260
1260
  };
1261
1261
 
1262
- const TRACK_BOX_CHANGE_EVENT_NAME = 'change';
1262
+ var TrackBoxEvents;
1263
+ (function (TrackBoxEvents) {
1264
+ TrackBoxEvents["CHANGE"] = "change";
1265
+ TrackBoxEvents["RESET"] = "reset";
1266
+ })(TrackBoxEvents || (TrackBoxEvents = {}));
1263
1267
  var ItemDisplayMethods;
1264
1268
  (function (ItemDisplayMethods) {
1265
1269
  ItemDisplayMethods[ItemDisplayMethods["CREATE"] = 0] = "CREATE";
@@ -1267,7 +1271,7 @@ var ItemDisplayMethods;
1267
1271
  ItemDisplayMethods[ItemDisplayMethods["DELETE"] = 2] = "DELETE";
1268
1272
  ItemDisplayMethods[ItemDisplayMethods["NOT_CHANGED"] = 3] = "NOT_CHANGED";
1269
1273
  })(ItemDisplayMethods || (ItemDisplayMethods = {}));
1270
- const DEFAULT_BUFFER_EXTREMUM_THRESHOLD = 15, DEFAULT_MAX_BUFFER_SEQUENCE_LENGTH = 30, DEFAULT_RESET_BUFFER_SIZE_TIMEOUT = 10000;
1274
+ const DEFAULT_BUFFER_EXTREMUM_THRESHOLD = 15, DEFAULT_MAX_BUFFER_SEQUENCE_LENGTH = 30, DEFAULT_RESET_BUFFER_SIZE_TIMEOUT = 10000, IS_NEW = 'isNew';
1271
1275
  /**
1272
1276
  * An object that performs tracking, calculations and caching.
1273
1277
  * @link https://github.com/DjonnyX/ng-virtual-list/blob/19.x/projects/ng-virtual-list/src/lib/utils/trackBox.ts
@@ -1343,7 +1347,7 @@ class TrackBox extends CacheMap {
1343
1347
  get crudDetected() { return this._crudDetected; }
1344
1348
  fireChangeIfNeed() {
1345
1349
  if (this.changesDetected()) {
1346
- this.dispatch(TRACK_BOX_CHANGE_EVENT_NAME, this._version);
1350
+ this.dispatch(TrackBoxEvents.CHANGE, this._version);
1347
1351
  }
1348
1352
  }
1349
1353
  _previousTotalSize = 0;
@@ -1359,7 +1363,7 @@ class TrackBox extends CacheMap {
1359
1363
  _maxBufferSize = this._defaultBufferSize;
1360
1364
  _resetBufferSizeTimeout = DEFAULT_RESET_BUFFER_SIZE_TIMEOUT;
1361
1365
  _resetBufferSizeTimer;
1362
- isInit = true;
1366
+ isReseted = true;
1363
1367
  lifeCircle() {
1364
1368
  this.fireChangeIfNeed();
1365
1369
  this.lifeCircleDo();
@@ -1372,11 +1376,19 @@ class TrackBox extends CacheMap {
1372
1376
  console.warn('Attention! The collection must be immutable.');
1373
1377
  return;
1374
1378
  }
1375
- if (this.isInit && !(!this._previousCollection || this._previousCollection.length === 0)) {
1376
- this.isInit = false;
1379
+ let reseted = this.isReseted;
1380
+ if (reseted) {
1381
+ if (!(!this._previousCollection || this._previousCollection.length === 0)) {
1382
+ reseted = false;
1383
+ }
1384
+ }
1385
+ if (!reseted && (!currentCollection || currentCollection.length === 0)) {
1386
+ reseted = true;
1377
1387
  }
1388
+ this.isReseted = reseted;
1389
+ this.dispatch(TrackBoxEvents.RESET, reseted);
1378
1390
  this.updateCache(this._previousCollection, currentCollection, itemSize);
1379
- this._previousCollection = currentCollection;
1391
+ this._previousCollection = [...(currentCollection || [])];
1380
1392
  }
1381
1393
  /**
1382
1394
  * Update the cache of items from the list
@@ -1599,7 +1611,7 @@ class TrackBox extends CacheMap {
1599
1611
  leftItemsOffset = rightItemsOffset = bufferSize;
1600
1612
  }
1601
1613
  let itemsFromStartToScrollEnd = -1, itemsFromDisplayEndToOffsetEnd = 0, itemsFromStartToDisplayEnd = -1, leftItemLength = 0, rightItemLength = 0, leftItemsWeight = 0, rightItemsWeight = 0, leftHiddenItemsWeight = 0, totalItemsToDisplayEndWeight = 0, leftSizeOfAddedItems = 0, leftSizeOfUpdatedItems = 0, leftSizeOfDeletedItems = 0, itemById = undefined, itemByIdPos = 0, targetDisplayItemIndex = -1, isTargetInOverscroll = false, actualScrollSize = itemByIdPos, totalSize = 0, startIndex, isFromItemIdFound = false, deltaFromStartCreation = 0;
1602
- let isNew = !this.isInit && (scrollSize === 0);
1614
+ let isNew = !this.isReseted && (scrollSize === 0);
1603
1615
  // If the list is dynamic or there are new elements in the collection, then it switches to the long algorithm.
1604
1616
  if (dynamicSize) {
1605
1617
  let y = 0, stickyCollectionItem = undefined, stickyComponentSize = 0;
@@ -1610,7 +1622,7 @@ class TrackBox extends CacheMap {
1610
1622
  const bounds = map.get(id) || { width: typicalItemSize, height: typicalItemSize };
1611
1623
  componentSize = bounds[sizeProperty];
1612
1624
  itemDisplayMethod = bounds?.method ?? ItemDisplayMethods.UPDATE;
1613
- const isItemNew = bounds.isNew ?? this._isLazy;
1625
+ const isItemNew = bounds?.[IS_NEW] ?? this._isLazy;
1614
1626
  if (!isItemNew && (!this._isLazy || !itemConfigMap[collection[0].id]?.sticky)) {
1615
1627
  isNew = false;
1616
1628
  }
@@ -1748,7 +1760,7 @@ class TrackBox extends CacheMap {
1748
1760
  if (map.has(id)) {
1749
1761
  const bounds = map.get(id);
1750
1762
  itemDisplayMethod = bounds?.method ?? ItemDisplayMethods.UPDATE;
1751
- const isItemNew = bounds.isNew ?? this._isLazy;
1763
+ const isItemNew = bounds?.[IS_NEW] ?? this._isLazy;
1752
1764
  if (!isItemNew && (!this._isLazy || !itemConfigMap[collection[0].id]?.sticky)) {
1753
1765
  isNew = false;
1754
1766
  }
@@ -1866,7 +1878,7 @@ class TrackBox extends CacheMap {
1866
1878
  height: isVertical ? size : normalizedItemHeight,
1867
1879
  delta: 0,
1868
1880
  }, config = {
1869
- new: cache.isNew === true,
1881
+ new: cache?.[IS_NEW] === true,
1870
1882
  odd: isOdd,
1871
1883
  even: !isOdd,
1872
1884
  isVertical,
@@ -1908,7 +1920,7 @@ class TrackBox extends CacheMap {
1908
1920
  height: h,
1909
1921
  delta: 0,
1910
1922
  }, config = {
1911
- new: cache.isNew === true,
1923
+ new: cache?.[IS_NEW] === true,
1912
1924
  odd: isOdd,
1913
1925
  even: !isOdd,
1914
1926
  isVertical,
@@ -1949,7 +1961,7 @@ class TrackBox extends CacheMap {
1949
1961
  height: isVertical ? size : normalizedItemHeight,
1950
1962
  delta: 0,
1951
1963
  }, config = {
1952
- new: cache.isNew === true,
1964
+ new: cache?.[IS_NEW] === true,
1953
1965
  odd: isOdd,
1954
1966
  even: !isOdd,
1955
1967
  isVertical,
@@ -2658,10 +2670,25 @@ class NgVirtualListComponent {
2658
2670
  this._cacheVersion.set(v);
2659
2671
  };
2660
2672
  _cacheVersion = signal(-1);
2673
+ _isResetedReachStart = true;
2674
+ _onTrackBoxResetHandler = (v) => {
2675
+ if (v) {
2676
+ this._isResetedReachStart = true;
2677
+ const container = this._container()?.nativeElement;
2678
+ if (container) {
2679
+ const params = {
2680
+ [this._isVertical ? TOP_PROP_NAME : LEFT_PROP_NAME]: 0,
2681
+ behavior: BEHAVIOR_INSTANT,
2682
+ };
2683
+ container.scrollTo(params);
2684
+ }
2685
+ }
2686
+ };
2661
2687
  constructor() {
2662
2688
  NgVirtualListComponent.__nextId = NgVirtualListComponent.__nextId + 1 === Number.MAX_SAFE_INTEGER
2663
2689
  ? 0 : NgVirtualListComponent.__nextId + 1;
2664
2690
  this._id = NgVirtualListComponent.__nextId;
2691
+ this._trackBox.addEventListener(TrackBoxEvents.RESET, this._onTrackBoxResetHandler);
2665
2692
  this._service.initialize(this._trackBox);
2666
2693
  this._service.itemToFocus = this.itemToFocus;
2667
2694
  this._initialized = signal(false);
@@ -2674,12 +2701,13 @@ class NgVirtualListComponent {
2674
2701
  this._service.listElement = v.nativeElement;
2675
2702
  })).subscribe();
2676
2703
  const $trackBy = toObservable(this.trackBy), $selectByClick = toObservable(this.selectByClick), $collapseByClick = toObservable(this.collapseByClick), $isScrollStart = toObservable(this._isScrollStart), $isScrollFinished = toObservable(this._isScrollFinished);
2677
- $isScrollStart.pipe(takeUntilDestroyed(), distinctUntilChanged(), skip(1), tap(v => {
2678
- if (v) {
2704
+ $isScrollStart.pipe(takeUntilDestroyed(), distinctUntilChanged(), tap(v => {
2705
+ if (v && !this._isResetedReachStart) {
2679
2706
  this.onScrollReachStart.emit();
2680
2707
  }
2708
+ this._isResetedReachStart = false;
2681
2709
  })).subscribe();
2682
- $isScrollFinished.pipe(takeUntilDestroyed(), distinctUntilChanged(), skip(1), tap(v => {
2710
+ $isScrollFinished.pipe(takeUntilDestroyed(), distinctUntilChanged(), tap(v => {
2683
2711
  if (v) {
2684
2712
  this.onScrollReachEnd.emit();
2685
2713
  }
@@ -2774,9 +2802,11 @@ class NgVirtualListComponent {
2774
2802
  this.resetBoundsSize(isVertical, totalSize);
2775
2803
  this.createDisplayComponentsIfNeed(displayItems);
2776
2804
  this.tracking();
2777
- const scrollLength = (this._isVertical ? this._container()?.nativeElement.scrollHeight ?? 0 : this._container()?.nativeElement.scrollWidth) ?? 0, actualScrollLength = scrollLength === 0 ? 0 : scrollLength - (this._isVertical ? height : width), scrollPosition = actualScrollSize + this._trackBox.delta;
2778
- this._isScrollStart.set(scrollPosition === 0);
2779
- this._isScrollFinished.set(scrollPosition === actualScrollLength);
2805
+ const scrollLength = (this._isVertical ? this._container()?.nativeElement.scrollHeight ?? 0 : this._container()?.nativeElement.scrollWidth) ?? 0, actualScrollLength = scrollLength === 0 ? 0 : Math.round(scrollLength - (this._isVertical ? height : width)), scrollPosition = actualScrollSize + this._trackBox.delta;
2806
+ if (actualScrollLength > 0) {
2807
+ this._isScrollStart.set(scrollPosition === 0);
2808
+ this._isScrollFinished.set(scrollPosition === actualScrollLength);
2809
+ }
2780
2810
  if (this._isSnappingMethodAdvanced) {
2781
2811
  this.updateRegularRenderer();
2782
2812
  }
@@ -2845,13 +2875,13 @@ class NgVirtualListComponent {
2845
2875
  }
2846
2876
  listenCacheChangesIfNeed(value) {
2847
2877
  if (value) {
2848
- if (!this._trackBox.hasEventListener(TRACK_BOX_CHANGE_EVENT_NAME, this._onTrackBoxChangeHandler)) {
2849
- this._trackBox.addEventListener(TRACK_BOX_CHANGE_EVENT_NAME, this._onTrackBoxChangeHandler);
2878
+ if (!this._trackBox.hasEventListener(TrackBoxEvents.CHANGE, this._onTrackBoxChangeHandler)) {
2879
+ this._trackBox.addEventListener(TrackBoxEvents.CHANGE, this._onTrackBoxChangeHandler);
2850
2880
  }
2851
2881
  }
2852
2882
  else {
2853
- if (this._trackBox.hasEventListener(TRACK_BOX_CHANGE_EVENT_NAME, this._onTrackBoxChangeHandler)) {
2854
- this._trackBox.removeEventListener(TRACK_BOX_CHANGE_EVENT_NAME, this._onTrackBoxChangeHandler);
2883
+ if (this._trackBox.hasEventListener(TrackBoxEvents.CHANGE, this._onTrackBoxChangeHandler)) {
2884
+ this._trackBox.removeEventListener(TrackBoxEvents.CHANGE, this._onTrackBoxChangeHandler);
2855
2885
  }
2856
2886
  }
2857
2887
  }