Wrote an Angular 13 component that draws something in a div whenever the window resizes.
The problem is getting the rendered width of the div. If I do not use setTimeout() with a 170ms delay, this.treemap.nativeElement.offsetWidth
is zero.
As the treemap has to re-render each time the window resizes, I also tried dispatching a window resize event from ngAfterViewInit() but it also seems to happen too fast (so again, this.treemap.nativeElement.offsetWidth
is zero).
Relevent part of the template...
<div #treemap ></div>
and abbreviated code...
// Details omitted for brevity
export class TreemapComponent implements AfterViewInit {
@ViewChild('treemap') treemap!: ElementRef
@HostListener('window:resize', ['$event'])
private render() {
const width = this.treemap.nativeElement.offsetWidth
// code that successfully renders a treemap in the div as long as width != 0
}
callHack(): void {
setTimeout(() => this.render(), 170) // testing shows 170ms is lowest possible
}
ngAfterViewInit(): void {
this.callHack()
// window.dispatchEvent(new Event('resize')) // happens too fast (offsetWidth = 0)
}
Is AfterViewInit the wrong lifecycle event hook (this post suggested ngAfterViewInit)?
Is there a less-hacky approach to making this work in Angular 13?
CodePudding user response:
You can use a ResizeObserver
to observe the element itself rather than the window.
export class TreemapComponent implements AfterViewInit, OnDestroy {
@ViewChild('treemap') treemap!: ElementRef;
treemapObserver = new ResizeObserver(() => this.render());
private render() {
const width = this.treemap.nativeElement.offsetWidth;
// code that successfully renders a treemap in the div as long as width != 0
}
ngAfterViewInit(): void {
this.treemapObserver.observe(this.treemap.nativeElement);
}
ngOnDestroy() {
this.treemapObserver.unobserve(this.treemap.nativeElement);
}
}
Credit to this answer: https://stackoverflow.com/a/39312522/12914833
CodePudding user response:
Try calling ngAfterViewChecked() instead of ngAfterViewInit()