Browse Source

update: enhancement for infinite scroll support

pull/23670/head
sumeyye 1 year ago
parent
commit
2996b47823
  1. 55
      npm/ng-packs/packages/components/extensible/src/lib/components/extensible-table/extensible-table.component.ts

55
npm/ng-packs/packages/components/extensible/src/lib/components/extensible-table/extensible-table.component.ts

@ -10,16 +10,16 @@ import {
Input, Input,
LOCALE_ID, LOCALE_ID,
OnChanges, OnChanges,
OnDestroy,
Output, Output,
signal, signal,
SimpleChanges, SimpleChanges,
TemplateRef, TemplateRef,
TrackByFunction, TrackByFunction,
ViewChild,
} from '@angular/core'; } from '@angular/core';
import { AsyncPipe, NgComponentOutlet, NgTemplateOutlet } from '@angular/common'; import { AsyncPipe, NgComponentOutlet, NgTemplateOutlet } from '@angular/common';
import { Observable, filter, map } from 'rxjs'; import { Observable, filter, map, Subject, debounceTime, distinctUntilChanged } from 'rxjs';
import { NgbTooltip } from '@ng-bootstrap/ng-bootstrap'; import { NgbTooltip } from '@ng-bootstrap/ng-bootstrap';
import { NgxDatatableModule, SelectionType } from '@swimlane/ngx-datatable'; import { NgxDatatableModule, SelectionType } from '@swimlane/ngx-datatable';
@ -75,7 +75,7 @@ const DEFAULT_ACTIONS_COLUMN_WIDTH = 150;
templateUrl: './extensible-table.component.html', templateUrl: './extensible-table.component.html',
changeDetection: ChangeDetectionStrategy.OnPush, changeDetection: ChangeDetectionStrategy.OnPush,
}) })
export class ExtensibleTableComponent<R = any> implements OnChanges, AfterViewInit { export class ExtensibleTableComponent<R = any> implements OnChanges, AfterViewInit, OnDestroy {
readonly #injector = inject(Injector); readonly #injector = inject(Injector);
readonly getInjected = this.#injector.get.bind(this.#injector); readonly getInjected = this.#injector.get.bind(this.#injector);
protected readonly cdr = inject(ChangeDetectorRef); protected readonly cdr = inject(ChangeDetectorRef);
@ -113,13 +113,14 @@ export class ExtensibleTableComponent<R = any> implements OnChanges, AfterViewIn
this._selectionType = typeof value === 'string' ? SelectionType[value] : value; this._selectionType = typeof value === 'string' ? SelectionType[value] : value;
} }
_selectionType: SelectionType = SelectionType.multiClick; _selectionType: SelectionType = SelectionType.multiClick;
@Input() selected: any[] = []; @Input() selected: any[] = [];
@Output() selectionChange = new EventEmitter<any[]>(); @Output() selectionChange = new EventEmitter<any[]>();
// Infinite scroll configuration
@Input() infiniteScroll = false; @Input() infiniteScroll = false;
@Input() isLoading = false; @Input() isLoading = false;
@Input() scrollThreshold = 10;
@Output() loadMore = new EventEmitter<void>(); @Output() loadMore = new EventEmitter<void>();
@Input() tableHeight: number; @Input() tableHeight: number;
@ -134,6 +135,12 @@ export class ExtensibleTableComponent<R = any> implements OnChanges, AfterViewIn
// Signal for actions column width // Signal for actions column width
private readonly _actionsColumnWidth = signal<number | undefined>(DEFAULT_ACTIONS_COLUMN_WIDTH); private readonly _actionsColumnWidth = signal<number | undefined>(DEFAULT_ACTIONS_COLUMN_WIDTH);
// Infinite scroll: debounced load more subject
private readonly loadMoreSubject = new Subject<void>();
private readonly loadMoreSubscription = this.loadMoreSubject
.pipe(debounceTime(100), distinctUntilChanged())
.subscribe(() => this.triggerLoadMore());
readonly columnWidths = computed(() => { readonly columnWidths = computed(() => {
const actionsColumn = this._actionsColumnWidth(); const actionsColumn = this._actionsColumnWidth();
const widths = [actionsColumn]; const widths = [actionsColumn];
@ -221,7 +228,6 @@ export class ExtensibleTableComponent<R = any> implements OnChanges, AfterViewIn
return record; return record;
}); });
} }
isVisibleActions(rowData: any): boolean { isVisibleActions(rowData: any): boolean {
@ -252,17 +258,34 @@ export class ExtensibleTableComponent<R = any> implements OnChanges, AfterViewIn
this.selectionChange.emit(selected); this.selectionChange.emit(selected);
} }
onScroll(scrollEvent) { onScroll(scrollEvent: Event): void {
if ( if (!this.shouldHandleScroll()) {
this.infiniteScroll && return;
!this.isLoading && }
scrollEvent?.target?.offsetHeight + scrollEvent?.target?.scrollTop >=
scrollEvent?.target?.scrollHeight - 1 const target = scrollEvent.target as HTMLElement;
) { if (!target) {
this.loadMore.emit(); return;
}
if (this.isNearScrollBottom(target)) {
this.loadMoreSubject.next();
} }
} }
private shouldHandleScroll(): boolean {
return this.infiniteScroll && !this.isLoading;
}
private isNearScrollBottom(element: HTMLElement): boolean {
const { offsetHeight, scrollTop, scrollHeight } = element;
return offsetHeight + scrollTop >= scrollHeight - this.scrollThreshold;
}
private triggerLoadMore(): void {
this.loadMore.emit();
}
getTableHeight() { getTableHeight() {
if (!this.infiniteScroll) return 'auto'; if (!this.infiniteScroll) return 'auto';
@ -277,4 +300,8 @@ export class ExtensibleTableComponent<R = any> implements OnChanges, AfterViewIn
}); });
} }
} }
ngOnDestroy(): void {
this.loadMoreSubscription.unsubscribe();
}
} }

Loading…
Cancel
Save