Browse Source

update: migrating the loading indicator logic to list directive

pull/20804/head
sumeyyeKurtulus 2 years ago
parent
commit
021f95d839
  1. 81
      npm/ng-packs/packages/theme-shared/src/lib/directives/ngx-datatable-default.directive.ts
  2. 101
      npm/ng-packs/packages/theme-shared/src/lib/directives/ngx-datatable-list.directive.ts

81
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<boolean>(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();
}
}
}

101
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 = `
<div class="d-flex justify-content-center align-items-center m-1">
<div class="spinner-border" role="status" id="loading">
<span class="visually-hidden">Loading...</span>
</div>
</div>
`;
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),
};

Loading…
Cancel
Save