ng-virtual-list 18.7.1 → 18.7.2

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.
@@ -69,6 +69,7 @@ const DEFAULT_BUFFER_SIZE = 2;
69
69
  const DEFAULT_MAX_BUFFER_SIZE = 100;
70
70
  const DEFAULT_LIST_SIZE = 400;
71
71
  const DEFAULT_SNAP = false;
72
+ const DEFAULT_SELECT_BY_CLICK = true;
72
73
  const DEFAULT_ENABLED_BUFFER_OPTIMIZATION = false;
73
74
  const DEFAULT_DYNAMIC_SIZE = false;
74
75
  const TRACK_BY_PROPERTY_NAME = 'id';
@@ -155,6 +156,7 @@ class NgVirtualListService {
155
156
  set methodOfSelecting(v) {
156
157
  this._$methodOfSelecting.next(v);
157
158
  }
159
+ selectByClick = DEFAULT_SELECT_BY_CLICK;
158
160
  _trackBox;
159
161
  constructor() {
160
162
  this._$methodOfSelecting.pipe(takeUntilDestroyed(), tap(v => {
@@ -181,25 +183,61 @@ class NgVirtualListService {
181
183
  })).subscribe();
182
184
  }
183
185
  setSelectedIds(ids) {
184
- this._$selectedIds.next(ids);
186
+ if (JSON.stringify(this._$selectedIds.getValue()) !== JSON.stringify(ids)) {
187
+ this._$selectedIds.next(ids);
188
+ }
185
189
  }
186
190
  itemClick(data) {
187
191
  this._$itemClick.next(data);
192
+ if (this.selectByClick) {
193
+ this.select(data);
194
+ }
195
+ }
196
+ /**
197
+ * Selects a list item
198
+ * @param data
199
+ * @param selected - If the value is undefined, then the toggle method is executed, if false or true, then the selection/deselection is performed.
200
+ */
201
+ select(data, selected = undefined) {
188
202
  if (data && data.config.selectable) {
189
203
  switch (this._$methodOfSelecting.getValue()) {
190
204
  case MethodsForSelectingTypes.SELECT: {
191
205
  const curr = this._$selectedIds.getValue();
192
- this._$selectedIds.next(curr !== data?.id ? data?.id : undefined);
206
+ if (selected === undefined) {
207
+ this._$selectedIds.next(curr !== data?.id ? data?.id : undefined);
208
+ }
209
+ else {
210
+ this._$selectedIds.next(selected ? data?.id : undefined);
211
+ }
193
212
  break;
194
213
  }
195
214
  case MethodsForSelectingTypes.MULTI_SELECT: {
196
215
  const curr = [...(this._$selectedIds.getValue() || [])], index = curr.indexOf(data.id);
197
- if (index > -1) {
198
- curr.splice(index, 1);
199
- this._$selectedIds.next(curr);
216
+ if (selected === undefined) {
217
+ if (index > -1) {
218
+ curr.splice(index, 1);
219
+ this._$selectedIds.next(curr);
220
+ }
221
+ else {
222
+ this._$selectedIds.next([...curr, data.id]);
223
+ }
224
+ }
225
+ else if (selected) {
226
+ if (index > -1) {
227
+ this._$selectedIds.next(curr);
228
+ }
229
+ else {
230
+ this._$selectedIds.next([...curr, data.id]);
231
+ }
200
232
  }
201
233
  else {
202
- this._$selectedIds.next([...curr, data.id]);
234
+ if (index > -1) {
235
+ curr.splice(index, 1);
236
+ this._$selectedIds.next(curr);
237
+ }
238
+ else {
239
+ this._$selectedIds.next(curr);
240
+ }
203
241
  }
204
242
  break;
205
243
  }
@@ -243,6 +281,7 @@ class NgVirtualListItemComponent extends BaseVirtualListItemComponent {
243
281
  _service = inject(NgVirtualListService);
244
282
  _isSelected = false;
245
283
  config = signal({});
284
+ measures = signal(undefined);
246
285
  _part = PART_DEFAULT_ITEM;
247
286
  get part() { return this._part; }
248
287
  regular = false;
@@ -255,6 +294,7 @@ class NgVirtualListItemComponent extends BaseVirtualListItemComponent {
255
294
  this._data = v;
256
295
  this.updatePartStr(v, this._isSelected);
257
296
  this.updateConfig(v);
297
+ this.updateMeasures(v);
258
298
  this.update();
259
299
  this.data.set(v);
260
300
  this._cdr.detectChanges();
@@ -282,6 +322,14 @@ class NgVirtualListItemComponent extends BaseVirtualListItemComponent {
282
322
  get element() {
283
323
  return this._elementRef.nativeElement;
284
324
  }
325
+ _selectHandler = (data) =>
326
+ /**
327
+ * Selects a list item
328
+ * @param selected - If the value is undefined, then the toggle method is executed, if false or true, then the selection/deselection is performed.
329
+ */
330
+ (selected = undefined) => {
331
+ this._service.select(data, selected);
332
+ };
285
333
  constructor() {
286
334
  super();
287
335
  this._id = this._service.generateComponentId();
@@ -309,11 +357,14 @@ class NgVirtualListItemComponent extends BaseVirtualListItemComponent {
309
357
  }
310
358
  this.updatePartStr(this._data, this._isSelected);
311
359
  this.updateConfig(this._data);
360
+ this.updateMeasures(this._data);
312
361
  })).subscribe();
313
362
  }
363
+ updateMeasures(v) {
364
+ this.measures.set(v?.measures ? { ...v.measures } : undefined);
365
+ }
314
366
  updateConfig(v) {
315
- this.config.set({ ...v?.config || {}, selected: this._isSelected });
316
- this._cdr.markForCheck();
367
+ this.config.set({ ...v?.config || {}, selected: this._isSelected, select: this._selectHandler(v) });
317
368
  }
318
369
  update() {
319
370
  const data = this._data, regular = this.regular, length = this._regularLength;
@@ -398,14 +449,14 @@ class NgVirtualListItemComponent extends BaseVirtualListItemComponent {
398
449
  this._service.itemClick(this._data);
399
450
  }
400
451
  static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "18.2.13", ngImport: i0, type: NgVirtualListItemComponent, deps: [], target: i0.ɵɵFactoryTarget.Component });
401
- static ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.0.0", version: "18.2.13", type: NgVirtualListItemComponent, selector: "ng-virtual-list-item", host: { attributes: { "role": "listitem" }, classAttribute: "ngvl__item" }, usesInheritance: true, ngImport: i0, template: "@if (data(); as item) {\r\n <div #listItem [part]=\"part\" class=\"ngvl-item__container\" [ngClass]=\"{'snapped': item.config.snapped,\r\n 'snapped-out': item.config.snappedOut}\" (click)=\"onClickHandler()\">\r\n @if (itemRenderer(); as renderer) {\r\n <ng-container [ngTemplateOutlet]=\"renderer\"\r\n [ngTemplateOutletContext]=\"{data: item.data || {}, config: config()}\" />\r\n }\r\n </div>\r\n}\r\n", styles: [":host{display:block;position:absolute;left:0;top:0;box-sizing:border-box;overflow:hidden}.ngvl-item__container{margin:0;padding:0;overflow:hidden;background-color:#fff;width:inherit;height:inherit}\n"], dependencies: [{ kind: "directive", type: i1.NgClass, selector: "[ngClass]", inputs: ["class", "ngClass"] }, { kind: "directive", type: i1.NgTemplateOutlet, selector: "[ngTemplateOutlet]", inputs: ["ngTemplateOutletContext", "ngTemplateOutlet", "ngTemplateOutletInjector"] }], changeDetection: i0.ChangeDetectionStrategy.OnPush });
452
+ static ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.0.0", version: "18.2.13", type: NgVirtualListItemComponent, selector: "ng-virtual-list-item", host: { attributes: { "role": "listitem" }, classAttribute: "ngvl__item" }, usesInheritance: true, ngImport: i0, template: "@if (data(); as item) {\r\n <div #listItem [part]=\"part\" class=\"ngvl-item__container\" [ngClass]=\"{'snapped': item.config.snapped,\r\n 'snapped-out': item.config.snappedOut}\" (click)=\"onClickHandler()\">\r\n @if (itemRenderer(); as renderer) {\r\n <ng-container [ngTemplateOutlet]=\"renderer\"\r\n [ngTemplateOutletContext]=\"{data: item.data || {}, measures: measures(), config: config()}\" />\r\n }\r\n </div>\r\n}\r\n", styles: [":host{display:block;position:absolute;left:0;top:0;box-sizing:border-box;overflow:hidden}.ngvl-item__container{margin:0;padding:0;overflow:hidden;background-color:#fff;width:inherit;height:inherit}\n"], dependencies: [{ kind: "directive", type: i1.NgClass, selector: "[ngClass]", inputs: ["class", "ngClass"] }, { kind: "directive", type: i1.NgTemplateOutlet, selector: "[ngTemplateOutlet]", inputs: ["ngTemplateOutletContext", "ngTemplateOutlet", "ngTemplateOutletInjector"] }], changeDetection: i0.ChangeDetectionStrategy.OnPush });
402
453
  }
403
454
  i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "18.2.13", ngImport: i0, type: NgVirtualListItemComponent, decorators: [{
404
455
  type: Component,
405
456
  args: [{ selector: 'ng-virtual-list-item', standalone: false, host: {
406
457
  'class': 'ngvl__item',
407
458
  'role': 'listitem',
408
- }, changeDetection: ChangeDetectionStrategy.OnPush, template: "@if (data(); as item) {\r\n <div #listItem [part]=\"part\" class=\"ngvl-item__container\" [ngClass]=\"{'snapped': item.config.snapped,\r\n 'snapped-out': item.config.snappedOut}\" (click)=\"onClickHandler()\">\r\n @if (itemRenderer(); as renderer) {\r\n <ng-container [ngTemplateOutlet]=\"renderer\"\r\n [ngTemplateOutletContext]=\"{data: item.data || {}, config: config()}\" />\r\n }\r\n </div>\r\n}\r\n", styles: [":host{display:block;position:absolute;left:0;top:0;box-sizing:border-box;overflow:hidden}.ngvl-item__container{margin:0;padding:0;overflow:hidden;background-color:#fff;width:inherit;height:inherit}\n"] }]
459
+ }, changeDetection: ChangeDetectionStrategy.OnPush, template: "@if (data(); as item) {\r\n <div #listItem [part]=\"part\" class=\"ngvl-item__container\" [ngClass]=\"{'snapped': item.config.snapped,\r\n 'snapped-out': item.config.snappedOut}\" (click)=\"onClickHandler()\">\r\n @if (itemRenderer(); as renderer) {\r\n <ng-container [ngTemplateOutlet]=\"renderer\"\r\n [ngTemplateOutletContext]=\"{data: item.data || {}, measures: measures(), config: config()}\" />\r\n }\r\n </div>\r\n}\r\n", styles: [":host{display:block;position:absolute;left:0;top:0;box-sizing:border-box;overflow:hidden}.ngvl-item__container{margin:0;padding:0;overflow:hidden;background-color:#fff;width:inherit;height:inherit}\n"] }]
409
460
  }], ctorParameters: () => [] });
410
461
 
411
462
  /**
@@ -1804,6 +1855,11 @@ class NgVirtualListComponent {
1804
1855
  * Sets the selected items.
1805
1856
  */
1806
1857
  selectedIds = input(undefined);
1858
+ /**
1859
+ * If false, the element is selected using the config.select method passed to the template;
1860
+ * if true, the element is selected by clicking on it. The default value is true.
1861
+ */
1862
+ selectByClick = input(DEFAULT_SELECT_BY_CLICK);
1807
1863
  /**
1808
1864
  * Determines whether elements will snap. Default value is "true".
1809
1865
  */
@@ -2002,7 +2058,10 @@ class NgVirtualListComponent {
2002
2058
  this._initialized = signal(false);
2003
2059
  this.$initialized = toObservable(this._initialized);
2004
2060
  this._trackBox.displayComponents = this._displayComponents;
2005
- const $trackBy = toObservable(this.trackBy);
2061
+ const $trackBy = toObservable(this.trackBy), $selectByClick = toObservable(this.selectByClick);
2062
+ $selectByClick.pipe(takeUntilDestroyed(), tap(v => {
2063
+ this._service.selectByClick = v;
2064
+ })).subscribe();
2006
2065
  $trackBy.pipe(takeUntilDestroyed(), tap(v => {
2007
2066
  this._trackBox.trackingPropertyName = v;
2008
2067
  })).subscribe();
@@ -2084,10 +2143,19 @@ class NgVirtualListComponent {
2084
2143
  this._service.$itemClick.pipe(takeUntilDestroyed(), tap(v => {
2085
2144
  this.onItemClick.emit(v);
2086
2145
  })).subscribe();
2087
- this._service.$selectedIds.pipe(takeUntilDestroyed(), tap(v => {
2088
- this.onSelect.emit(v);
2146
+ let isSelectedIdsFirstEmit = 0;
2147
+ this._service.$selectedIds.pipe(takeUntilDestroyed(), distinctUntilChanged(), tap(v => {
2148
+ if (this.isSingleSelecting || (this.isMultiSelecting && isSelectedIdsFirstEmit >= 2)) {
2149
+ const curr = this.selectedIds();
2150
+ if ((this.isSingleSelecting && JSON.stringify(v) !== JSON.stringify(curr)) || (isSelectedIdsFirstEmit === 2 && JSON.stringify(v) !== JSON.stringify(curr)) || isSelectedIdsFirstEmit > 2) {
2151
+ this.onSelect.emit(v);
2152
+ }
2153
+ }
2154
+ if (isSelectedIdsFirstEmit < 3) {
2155
+ isSelectedIdsFirstEmit++;
2156
+ }
2089
2157
  })).subscribe();
2090
- $selectedIds.pipe(takeUntilDestroyed(), tap(v => {
2158
+ $selectedIds.pipe(takeUntilDestroyed(), distinctUntilChanged(), tap(v => {
2091
2159
  this._service.setSelectedIds(v);
2092
2160
  })).subscribe();
2093
2161
  }
@@ -2351,7 +2419,7 @@ class NgVirtualListComponent {
2351
2419
  }
2352
2420
  }
2353
2421
  static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "18.2.13", ngImport: i0, type: NgVirtualListComponent, deps: [], target: i0.ɵɵFactoryTarget.Component });
2354
- static ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.0.0", version: "18.2.13", type: NgVirtualListComponent, selector: "ng-virtual-list", inputs: { items: { classPropertyName: "items", publicName: "items", isSignal: true, isRequired: true, transformFunction: null }, selectedIds: { classPropertyName: "selectedIds", publicName: "selectedIds", isSignal: true, isRequired: false, transformFunction: null }, snap: { classPropertyName: "snap", publicName: "snap", isSignal: true, isRequired: false, transformFunction: null }, enabledBufferOptimization: { classPropertyName: "enabledBufferOptimization", publicName: "enabledBufferOptimization", isSignal: true, isRequired: false, transformFunction: null }, itemRenderer: { classPropertyName: "itemRenderer", publicName: "itemRenderer", isSignal: true, isRequired: true, transformFunction: null }, stickyMap: { classPropertyName: "stickyMap", publicName: "stickyMap", isSignal: true, isRequired: false, transformFunction: null }, itemConfigMap: { classPropertyName: "itemConfigMap", publicName: "itemConfigMap", isSignal: true, isRequired: false, transformFunction: null }, itemSize: { classPropertyName: "itemSize", publicName: "itemSize", isSignal: true, isRequired: false, transformFunction: null }, dynamicSize: { classPropertyName: "dynamicSize", publicName: "dynamicSize", isSignal: true, isRequired: false, transformFunction: null }, direction: { classPropertyName: "direction", publicName: "direction", isSignal: true, isRequired: false, transformFunction: null }, itemsOffset: { classPropertyName: "itemsOffset", publicName: "itemsOffset", isSignal: true, isRequired: false, transformFunction: null }, bufferSize: { classPropertyName: "bufferSize", publicName: "bufferSize", isSignal: true, isRequired: false, transformFunction: null }, maxBufferSize: { classPropertyName: "maxBufferSize", publicName: "maxBufferSize", isSignal: true, isRequired: false, transformFunction: null }, snappingMethod: { classPropertyName: "snappingMethod", publicName: "snappingMethod", isSignal: true, isRequired: false, transformFunction: null }, methodForSelecting: { classPropertyName: "methodForSelecting", publicName: "methodForSelecting", isSignal: true, isRequired: false, transformFunction: null }, trackBy: { classPropertyName: "trackBy", publicName: "trackBy", isSignal: true, isRequired: false, transformFunction: null } }, outputs: { onScroll: "onScroll", onScrollEnd: "onScrollEnd", onViewportChange: "onViewportChange", onItemClick: "onItemClick", onSelect: "onSelect" }, providers: [NgVirtualListService], viewQueries: [{ propertyName: "_snappedContainer", first: true, predicate: ["snapped"], descendants: true, isSignal: true }, { propertyName: "_container", first: true, predicate: ["container"], descendants: true, isSignal: true }, { propertyName: "_list", first: true, predicate: ["list"], descendants: true, isSignal: true }, { propertyName: "_listContainerRef", first: true, predicate: ["renderersContainer"], descendants: true, read: ViewContainerRef }, { propertyName: "_snapContainerRef", first: true, predicate: ["snapRendererContainer"], descendants: true, read: ViewContainerRef }], ngImport: i0, template: "@if (snap()) {\r\n <div #snapped part=\"snapped-item\" class=\"ngvl__list-snapper\">\r\n <ng-container #snapRendererContainer></ng-container>\r\n </div>\r\n}\r\n<div #container part=\"scroller\" class=\"ngvl__scroller\">\r\n <div [attr.aria-orientation]=\"orientation\" #list part=\"list\" class=\"ngvl__list\">\r\n <ng-container #renderersContainer></ng-container>\r\n </div>\r\n</div>", styles: [":host{position:relative;display:block;width:400px;overflow:hidden}:host(.horizontal){height:48px}:host(.horizontal) .ngvl__list{display:inline-flex}:host(.horizontal) .ngvl__scroller{overflow:auto hidden}:host(.vertical) .ngvl__scroller{overflow:hidden auto}:host(.vertical){height:320px}.ngvl__scroller{overflow:auto;width:100%;height:100%}.ngvl__list-snapper{pointer-events:none;position:absolute;list-style:none;left:0;top:0;z-index:1}.ngvl__list{position:relative;list-style:none;padding:0;margin:0;width:100%;height:100%}\n"], changeDetection: i0.ChangeDetectionStrategy.OnPush, encapsulation: i0.ViewEncapsulation.ShadowDom });
2422
+ static ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.0.0", version: "18.2.13", type: NgVirtualListComponent, selector: "ng-virtual-list", inputs: { items: { classPropertyName: "items", publicName: "items", isSignal: true, isRequired: true, transformFunction: null }, selectedIds: { classPropertyName: "selectedIds", publicName: "selectedIds", isSignal: true, isRequired: false, transformFunction: null }, selectByClick: { classPropertyName: "selectByClick", publicName: "selectByClick", isSignal: true, isRequired: false, transformFunction: null }, snap: { classPropertyName: "snap", publicName: "snap", isSignal: true, isRequired: false, transformFunction: null }, enabledBufferOptimization: { classPropertyName: "enabledBufferOptimization", publicName: "enabledBufferOptimization", isSignal: true, isRequired: false, transformFunction: null }, itemRenderer: { classPropertyName: "itemRenderer", publicName: "itemRenderer", isSignal: true, isRequired: true, transformFunction: null }, stickyMap: { classPropertyName: "stickyMap", publicName: "stickyMap", isSignal: true, isRequired: false, transformFunction: null }, itemConfigMap: { classPropertyName: "itemConfigMap", publicName: "itemConfigMap", isSignal: true, isRequired: false, transformFunction: null }, itemSize: { classPropertyName: "itemSize", publicName: "itemSize", isSignal: true, isRequired: false, transformFunction: null }, dynamicSize: { classPropertyName: "dynamicSize", publicName: "dynamicSize", isSignal: true, isRequired: false, transformFunction: null }, direction: { classPropertyName: "direction", publicName: "direction", isSignal: true, isRequired: false, transformFunction: null }, itemsOffset: { classPropertyName: "itemsOffset", publicName: "itemsOffset", isSignal: true, isRequired: false, transformFunction: null }, bufferSize: { classPropertyName: "bufferSize", publicName: "bufferSize", isSignal: true, isRequired: false, transformFunction: null }, maxBufferSize: { classPropertyName: "maxBufferSize", publicName: "maxBufferSize", isSignal: true, isRequired: false, transformFunction: null }, snappingMethod: { classPropertyName: "snappingMethod", publicName: "snappingMethod", isSignal: true, isRequired: false, transformFunction: null }, methodForSelecting: { classPropertyName: "methodForSelecting", publicName: "methodForSelecting", isSignal: true, isRequired: false, transformFunction: null }, trackBy: { classPropertyName: "trackBy", publicName: "trackBy", isSignal: true, isRequired: false, transformFunction: null } }, outputs: { onScroll: "onScroll", onScrollEnd: "onScrollEnd", onViewportChange: "onViewportChange", onItemClick: "onItemClick", onSelect: "onSelect" }, providers: [NgVirtualListService], viewQueries: [{ propertyName: "_snappedContainer", first: true, predicate: ["snapped"], descendants: true, isSignal: true }, { propertyName: "_container", first: true, predicate: ["container"], descendants: true, isSignal: true }, { propertyName: "_list", first: true, predicate: ["list"], descendants: true, isSignal: true }, { propertyName: "_listContainerRef", first: true, predicate: ["renderersContainer"], descendants: true, read: ViewContainerRef }, { propertyName: "_snapContainerRef", first: true, predicate: ["snapRendererContainer"], descendants: true, read: ViewContainerRef }], ngImport: i0, template: "@if (snap()) {\r\n <div #snapped part=\"snapped-item\" class=\"ngvl__list-snapper\">\r\n <ng-container #snapRendererContainer></ng-container>\r\n </div>\r\n}\r\n<div #container part=\"scroller\" class=\"ngvl__scroller\">\r\n <div [attr.aria-orientation]=\"orientation\" #list part=\"list\" class=\"ngvl__list\">\r\n <ng-container #renderersContainer></ng-container>\r\n </div>\r\n</div>", styles: [":host{position:relative;display:block;width:400px;overflow:hidden}:host(.horizontal){height:48px}:host(.horizontal) .ngvl__list{display:inline-flex}:host(.horizontal) .ngvl__scroller{overflow:auto hidden}:host(.vertical) .ngvl__scroller{overflow:hidden auto}:host(.vertical){height:320px}.ngvl__scroller{overflow:auto;width:100%;height:100%}.ngvl__list-snapper{pointer-events:none;position:absolute;list-style:none;left:0;top:0;z-index:1}.ngvl__list{position:relative;list-style:none;padding:0;margin:0;width:100%;height:100%}\n"], changeDetection: i0.ChangeDetectionStrategy.OnPush, encapsulation: i0.ViewEncapsulation.ShadowDom });
2355
2423
  }
2356
2424
  i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "18.2.13", ngImport: i0, type: NgVirtualListComponent, decorators: [{
2357
2425
  type: Component,