From 021f95d83919c6da31d3e1f86fb03e59fb4aa0d4 Mon Sep 17 00:00:00 2001 From: sumeyyeKurtulus Date: Mon, 16 Sep 2024 14:57:42 +0300 Subject: [PATCH] update: migrating the loading indicator logic to list directive --- .../ngx-datatable-default.directive.ts | 81 +------------- .../ngx-datatable-list.directive.ts | 101 ++++++++++++++---- 2 files changed, 81 insertions(+), 101 deletions(-) diff --git a/npm/ng-packs/packages/theme-shared/src/lib/directives/ngx-datatable-default.directive.ts b/npm/ng-packs/packages/theme-shared/src/lib/directives/ngx-datatable-default.directive.ts index 58f315458c..e6ce7d3435 100644 --- a/npm/ng-packs/packages/theme-shared/src/lib/directives/ngx-datatable-default.directive.ts +++ b/npm/ng-packs/packages/theme-shared/src/lib/directives/ngx-datatable-default.directive.ts @@ -1,23 +1,8 @@ import { DOCUMENT } from '@angular/common'; -import { - AfterViewInit, - Directive, - effect, - ElementRef, - HostBinding, - inject, - Inject, - input, - Input, - OnDestroy, - OnInit, - Renderer2, - ViewContainerRef, -} from '@angular/core'; +import { AfterViewInit, Directive, HostBinding, Inject, Input, OnDestroy } from '@angular/core'; import { ColumnMode, DatatableComponent, ScrollerComponent } from '@swimlane/ngx-datatable'; import { fromEvent, Subscription } from 'rxjs'; import { debounceTime } from 'rxjs/operators'; -import { SpinnerComponent } from '../components'; @Directive({ // eslint-disable-next-line @angular-eslint/directive-selector @@ -25,18 +10,11 @@ import { SpinnerComponent } from '../components'; standalone: true, exportAs: 'ngxDatatableDefault', }) -export class NgxDatatableDefaultDirective implements OnInit, AfterViewInit, OnDestroy { +export class NgxDatatableDefaultDirective implements AfterViewInit, OnDestroy { @Input() class = 'material bordered'; - loadingIndicator = input(true); - - private _loading = true; - private mutationObserver: MutationObserver | null = null; private subscription = new Subscription(); private resizeDiff = 0; - private elRef = inject(ElementRef); - private renderer = inject(Renderer2); - private viewContainerRef = inject(ViewContainerRef); @HostBinding('class') get classes(): string { @@ -53,11 +31,6 @@ export class NgxDatatableDefaultDirective implements OnInit, AfterViewInit, OnDe this.table.rowHeight = 'auto'; this.table.scrollbarH = true; this.table.virtualization = false; - - effect(() => { - this._loading = this.loadingIndicator(); - this.updateLoadingIndicator(); - }); } private fixHorizontalGap(scroller: ScrollerComponent) { @@ -89,62 +62,12 @@ export class NgxDatatableDefaultDirective implements OnInit, AfterViewInit, OnDe this.subscription.add(subscription); } - private observeMutations() { - this.mutationObserver = new MutationObserver(() => { - if (this._loading) { - this.updateLoadingIndicator(); - } - }); - - this.mutationObserver.observe(this.elRef.nativeElement, { - childList: true, - subtree: true, - }); - } - - private updateLoadingIndicator() { - const progressElement = this.elRef.nativeElement.querySelector('datatable-progress'); - - if (this._loading) { - if (progressElement) { - this.renderer.removeChild(progressElement.parentNode, progressElement); - this.addSpinner(progressElement); - } - } else { - this.removeSpinner(); - } - } - - private addSpinner(placeholder: Comment) { - this.viewContainerRef.clear(); - - const spinnerRef = this.viewContainerRef.createComponent(SpinnerComponent); - - this.renderer.insertBefore( - placeholder.parentNode, - spinnerRef.location.nativeElement, - placeholder, - ); - this.renderer.removeChild(placeholder.parentNode, placeholder); - } - - private removeSpinner() { - this.viewContainerRef.clear(); - } - - ngOnInit() { - this.observeMutations(); - } - ngAfterViewInit() { this.fixStyleOnWindowResize(); } ngOnDestroy() { this.subscription.unsubscribe(); - if (this.mutationObserver) { - this.mutationObserver.disconnect(); - } } } diff --git a/npm/ng-packs/packages/theme-shared/src/lib/directives/ngx-datatable-list.directive.ts b/npm/ng-packs/packages/theme-shared/src/lib/directives/ngx-datatable-list.directive.ts index 811693f31f..e8e49bad34 100644 --- a/npm/ng-packs/packages/theme-shared/src/lib/directives/ngx-datatable-list.directive.ts +++ b/npm/ng-packs/packages/theme-shared/src/lib/directives/ngx-datatable-list.directive.ts @@ -8,14 +8,19 @@ import { SimpleChanges, inject, DestroyRef, + ViewContainerRef, + Renderer2, + AfterViewInit, } from '@angular/core'; import { takeUntilDestroyed } from '@angular/core/rxjs-interop'; import { DatatableComponent } from '@swimlane/ngx-datatable'; -import { ListService, LocalizationService } from '@abp/ng.core'; +import { combineLatest } from 'rxjs'; +import { ListService, LocalizationService, RouterWaitService } from '@abp/ng.core'; import { defaultNgxDatatableMessages, NGX_DATATABLE_MESSAGES, } from '../tokens/ngx-datatable-messages.token'; +import { SpinnerComponent } from '../components'; @Directive({ // eslint-disable-next-line @angular-eslint/directive-selector @@ -23,12 +28,17 @@ import { standalone: true, exportAs: 'ngxDatatableList', }) -export class NgxDatatableListDirective implements OnChanges, OnInit, DoCheck { +export class NgxDatatableListDirective implements OnChanges, OnInit, DoCheck, AfterViewInit { protected readonly table = inject(DatatableComponent); protected readonly cdRef = inject(ChangeDetectorRef); protected readonly destroyRef = inject(DestroyRef); protected readonly localizationService = inject(LocalizationService); protected readonly ngxDatatableMessages = inject(NGX_DATATABLE_MESSAGES, { optional: true }); + protected readonly routerWaitService = inject(RouterWaitService); + protected readonly viewContainerRef = inject(ViewContainerRef); + protected readonly renderer = inject(Renderer2); + + protected _loading = true; @Input() list!: ListService; @@ -40,28 +50,15 @@ export class NgxDatatableListDirective implements OnChanges, OnInit, DoCheck { this.refreshPageIfDataExist(); } + ngAfterViewInit() { + this.table.loadingIndicator = this._loading; + this.handleLoadingStart(); + } + ngOnInit() { this.subscribeToPage(); this.subscribeToSort(); - const indicator = document.createElement(`div`); - indicator.innerHTML = ` -
-
- Loading... -
-
- `; - - let ref: HTMLDivElement; - this.list.isLoading$.subscribe(isLoading => { - if (isLoading) { - ref = this.table.element.querySelector('.datatable-body').appendChild(indicator); - } else { - const { emptyMessage } = this.ngxDatatableMessages || defaultNgxDatatableMessages; - this.table.messages.emptyMessage = this.localizationService.instant(emptyMessage); - ref?.remove(); - } - }); + this.subscribeToLoadingState(); } ngOnChanges({ list }: SimpleChanges) { @@ -74,6 +71,66 @@ export class NgxDatatableListDirective implements OnChanges, OnInit, DoCheck { this.table.offset = page; } + protected subscribeToLoadingState() { + combineLatest([this.list.isLoading$, this.routerWaitService.getLoading$()]).subscribe( + ([listLoading, routerLoading]) => { + const isLoading = listLoading || routerLoading; + if (isLoading) { + this.handleLoadingStart(); + } else { + this.handleLoadingStop(); + } + }, + ); + } + + protected handleLoadingStop() { + if (this._loading) { + this.setLoadingState(false); + this.removeSpinner(); + } + } + + protected handleLoadingStart() { + if (!this._loading) { + this.setLoadingState(true); + this.updateLoadingIndicator(); + } + } + + protected setLoadingState(loading: boolean) { + this._loading = loading; + this.table.loadingIndicator = loading; + this.cdRef.detectChanges(); + } + + protected updateLoadingIndicator() { + const body = this.table.element.querySelector('datatable-body'); + const progress = this.table.element.querySelector('datatable-progress'); + + if (!body) { + return; + } + + if (progress) { + this.replaceLoadingIndicator(body, progress); + } + } + + protected replaceLoadingIndicator(parent: Element, placeholder: Element) { + this.viewContainerRef.clear(); + + const spinnerRef = this.viewContainerRef.createComponent(SpinnerComponent); + const spinnerElement = spinnerRef.location.nativeElement; + + this.renderer.insertBefore(parent, spinnerElement, placeholder); + this.renderer.removeChild(parent, placeholder); + } + + protected removeSpinner() { + this.viewContainerRef.clear(); + } + protected setInitialValues() { this.table.externalPaging = true; this.table.externalSorting = true; @@ -82,7 +139,7 @@ export class NgxDatatableListDirective implements OnChanges, OnInit, DoCheck { this.ngxDatatableMessages || defaultNgxDatatableMessages; this.table.messages = { - emptyMessage: '', + emptyMessage: this.localizationService.instant(emptyMessage), totalMessage: this.localizationService.instant(totalMessage), selectedMessage: this.localizationService.instant(selectedMessage), };