I am currently working on integrating a generic tooltip feature in Angular 5. In order to ensure proper positioning, especially centering relative to the target element, I need to obtain the width and height of the tooltip before it is rendered.
While I have already discovered how to acquire the dimensions of a component from this particular question, my challenge lies in setting the tooltip content first (allowing the browser to determine the size) for position calculation. Subsequently, I aim to set the position and apply a class for display.
Below is an excerpt of the code I am working with:
// tooltip.component.html
<div class="popup fade"
[ngClass]="tooltip?.isOpen ? 'show' : ''"
[style.left.px]="calculatedPos?.left"
[style.top.px]="calculatedPos?.top">
{{ tooltip?.text }}
</div>
// tooltip.component.ts
export class TooltipComponent {
public tooltip: any;
public calculatedPos: TooltipPosition = {
left: 0,
top: 0
}
constructor(private store: Store<any>, private ref: ElementRef) {
this.store.subscribe((state) => this.render(state));
}
render () {
let targetRect = this.tooltip.targetEl
&& this.tooltip.targetEl.nativeElement
&& this.tooltip.targetEl.nativeElement.getBoundingClientRect()
|| null;
let tooltipRect = this.ref
&& this.ref.nativeElement
&& this.ref.nativeElement.getBoundingClientRect()
|| null;
if (targetRect && tooltipRect) { // <-- tooltipRect.height /.width is zero here!
switch (this.tooltip.placement) {
case 'right':
this.calculatedPos = this.calculatePositionRight(targetRect, tooltipRect, this.tooltip.offset)
break;
// and so on...
}
}
I have experimented with using lifecycle hooks as follows:
ngAfterContentChecked
resulted in the same outcomengAfterViewChecked
produced an expectedExpressionChangedAfterItHasBeenCheckedError
ngOnChanges
did not trigger when rendering
Hence, I pose the following question: How can I obtain the dimensions of the Component before the content is rendered? Or alternatively, how can I detect the content being rendered and then update the position accordingly?
My initial consideration was to use a timeout to allow the component to render before setting the position (without the user noticing), but I am curious to explore any best practices that may exist.