Skip to content

Commit 5268ad7

Browse files
refactor: visibility observer
use `ResizeObserver` api to emit visibility change. Also auto recalculate table when table resize by parent containers.
1 parent b72a089 commit 5268ad7

File tree

1 file changed

+40
-19
lines changed

1 file changed

+40
-19
lines changed
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,5 @@
1-
import { Directive, ElementRef, EventEmitter, HostBinding, NgZone, OnDestroy, OnInit, Output } from '@angular/core';
1+
import { Directive, ElementRef, EventEmitter, HostBinding, Input, NgZone, OnDestroy, OnInit, Output } from '@angular/core';
2+
import { debounceTime, Observable, Subscriber } from 'rxjs';
23

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

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

21-
timeout: any;
22+
observer!: ResizeObserver;
23+
24+
/**
25+
* Throttle time in ms. Will emit this time after the resize.
26+
*/
27+
@Input() resizeThrottle = 100;
28+
/**
29+
* Emit the initial visibility without waiting throttle time.
30+
*/
31+
@Input() emitInitial = true;
32+
33+
private previousOffsetHeight = 0;
34+
private previousOffsetWidth = 0;
35+
2236

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

@@ -27,7 +41,7 @@ export class VisibilityDirective implements OnInit, OnDestroy {
2741
}
2842

2943
ngOnDestroy(): void {
30-
clearTimeout(this.timeout);
44+
this.observer.disconnect();
3145
}
3246

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

4155
runCheck(): void {
42-
const check = () => {
43-
// https://davidwalsh.name/offsetheight-visibility
44-
const { offsetHeight, offsetWidth } = this.element.nativeElement;
45-
46-
if (offsetHeight && offsetWidth) {
47-
clearTimeout(this.timeout);
48-
this.onVisibilityChange();
49-
} else {
50-
clearTimeout(this.timeout);
51-
this.zone.runOutsideAngular(() => {
52-
this.timeout = setTimeout(() => check(), 50);
53-
});
54-
}
55-
};
56-
57-
this.timeout = setTimeout(() => check());
56+
const resizeEvent = new Observable((subscriber: Subscriber<ResizeObserverEntry[]>) => {
57+
this.observer = new ResizeObserver(_entries => {
58+
const { offsetHeight, offsetWidth } = this.element.nativeElement;
59+
if ((offsetWidth && offsetHeight) && ((offsetHeight !== this.previousOffsetHeight) || (offsetWidth !== this.previousOffsetWidth))) {
60+
// First time emit immediately once table is visible
61+
if (!this.isVisible && this.emitInitial) {
62+
this.onVisibilityChange();
63+
} else {
64+
subscriber.next();
65+
}
66+
}
67+
this.previousOffsetHeight = offsetHeight;
68+
this.previousOffsetWidth = offsetWidth;
69+
});
70+
71+
this.observer.observe(this.element.nativeElement);
72+
});
73+
74+
resizeEvent.pipe(
75+
debounceTime(this.resizeThrottle)
76+
).subscribe(() => {
77+
this.onVisibilityChange();
78+
});
5879
}
5980
}

0 commit comments

Comments
 (0)