Skip to content

Commit

Permalink
refactor: visibility observer
Browse files Browse the repository at this point in the history
use `ResizeObserver` api to emit visibility change. Also auto recalculate table when table resize by parent containers.
  • Loading branch information
chintankavathia committed Jul 23, 2024
1 parent b72a089 commit 6de5892
Show file tree
Hide file tree
Showing 3 changed files with 46 additions and 20 deletions.
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
<div visibilityObserver (visible)="recalculate()">
<div visibilityObserver [resizeThrottle]="resizeThrottle" (visible)="recalculate()">
<div role="table">
<datatable-header
role="rowgroup"
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -468,6 +468,11 @@ export class DatatableComponent implements OnInit, DoCheck, AfterViewInit, After
*/
@Input() enableClearingSortState = false;

/**
* Throttle time in ms. Will recalculate table this time after the resize.
*/
@Input() resizeThrottle = 100;

/**
* Body was scrolled typically in a `scrollbarV:true` scenario.
*/
Expand Down
59 changes: 40 additions & 19 deletions projects/ngx-datatable/src/lib/directives/visibility.directive.ts
Original file line number Diff line number Diff line change
@@ -1,4 +1,5 @@
import { Directive, ElementRef, EventEmitter, HostBinding, NgZone, OnDestroy, OnInit, Output } from '@angular/core';
import { Directive, ElementRef, EventEmitter, HostBinding, Input, NgZone, OnDestroy, OnInit, Output } from '@angular/core';
import { debounceTime, Observable, Subscriber } from 'rxjs';

/**
* Visibility Observer Directive
Expand All @@ -18,7 +19,20 @@ export class VisibilityDirective implements OnInit, OnDestroy {

@Output() visible: EventEmitter<any> = new EventEmitter();

timeout: any;
observer!: ResizeObserver;

/**
* Throttle time in ms. Will emit this time after the resize.
*/
@Input() resizeThrottle = 100;
/**
* Emit the initial visibility without waiting throttle time.
*/
@Input() emitInitial = true;

private previousOffsetHeight = 0;
private previousOffsetWidth = 0;


constructor(private element: ElementRef, private zone: NgZone) {}

Expand All @@ -27,7 +41,7 @@ export class VisibilityDirective implements OnInit, OnDestroy {
}

ngOnDestroy(): void {
clearTimeout(this.timeout);
this.observer.disconnect();
}

onVisibilityChange(): void {
Expand All @@ -39,21 +53,28 @@ export class VisibilityDirective implements OnInit, OnDestroy {
}

runCheck(): void {
const check = () => {
// https://davidwalsh.name/offsetheight-visibility
const { offsetHeight, offsetWidth } = this.element.nativeElement;

if (offsetHeight && offsetWidth) {
clearTimeout(this.timeout);
this.onVisibilityChange();
} else {
clearTimeout(this.timeout);
this.zone.runOutsideAngular(() => {
this.timeout = setTimeout(() => check(), 50);
});
}
};

this.timeout = setTimeout(() => check());
const resizeEvent = new Observable((subscriber: Subscriber<ResizeObserverEntry[]>) => {
this.observer = new ResizeObserver(_entries => {
const { offsetHeight, offsetWidth } = this.element.nativeElement;
if ((offsetWidth && offsetHeight) && ((offsetHeight !== this.previousOffsetHeight) || (offsetWidth !== this.previousOffsetWidth))) {
// First time emit immediately once table is visible
if (!this.isVisible && this.emitInitial) {
this.onVisibilityChange();
} else {
subscriber.next();
}
}
this.previousOffsetHeight = offsetHeight;
this.previousOffsetWidth = offsetWidth;
});

this.observer.observe(this.element.nativeElement);
});

resizeEvent.pipe(
debounceTime(this.resizeThrottle)
).subscribe(() => {
this.onVisibilityChange();
});
}
}

0 comments on commit 6de5892

Please sign in to comment.