I'm implementing a generic tooltip in Angular 5. For the proper positioning (especially centering relative to the target element) I need to get the width and height of the tooltip before rendering it.
I already know how to get the dimensions of a component from this question. However, I need to set the content of the tooltip first (to let the browser determine the size) to calculate the position. Then, second, I want to set the position and add a class to show it.
Here is my code:
// 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 tried using lifecycleHooks:
- ngAfterContentCheckedleads to the same result
- ngAfterViewCheckedgives me (foreseeable) an- ExpressionChangedAfterItHasBeenCheckedError
- ngOnChangesis not called at all when rendering
So: How can I get the dimensions of the Component before the content is rendered? Or how can I detect the content being rendered and then updating the position?
My next thought would be using a timeout to first let the component render and then setting the position (without the user noticing) - but maybe there is a best practice, which I don't know about yet.
 
     
     
    