Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Angular 2 getBoundingClientRect from component

I have component like below which is basically a popover:

import {Component, Input, ViewChild} from 'angular2/core'

declare var $: any;

@Component({
  selector: 'popover',
  template: `
  <div id="temp" [ngStyle]="{'position':'absolute', 'z-index':'10000', 'top': y + 'px', left: x + 'px'}"
       [hidden]="hidden" #temp>
    <ng-content></ng-content>
  </div>
  `
})
export class Popover {

  @ViewChild("temp") temp;

  private hidden: boolean = true;
  private y: number = 0;
  private x: number = 0;

  show(target, shiftx = 0, shifty = 0){
    let position = $(target).offset();
    this.x = position.left + shiftx;
    this.y = position.top + shifty;
    this.hidden = false;

    console.log("#temp", this.temp.nativeElement.getBoundingClientRect()); //all 0s
    console.log("temp id", document.getElementById('temp').getBoundingClientRect()); //all 0s
  }

  hide(){
    this.hidden = true;
  }
}

Inside the show() method I am trying to get the result of getBoundingClientRect() but its returning 0 for all properties but when I type in document.getElementById("temp").getBoundingClientRect() from Chrome's console I get proper result with actual values in the properties. Why the difference and what can I do to get the actual value from my component?

like image 713
lbrahim Avatar asked Jun 17 '16 12:06

lbrahim


2 Answers

Instead of using setTimeout or lifecycle hooks that can be triggered more than once, I solved it with setting the Renderer to watch the window load event.

import { OnInit, Renderer2} from '@angular/core';

...

export class MyComponent implements  OnInit {

    constructor(private el: ElementRef, private render: Renderer2) {}

    ngOnInit() {
        this.render.listen('window', 'load', () => {
            const rect = this.el.nativeElement.getBoundingClientRect().top;
        })
    }

}

Maybe this helps someone's usecase.

like image 72
Anca Spatariu Avatar answered Nov 15 '22 14:11

Anca Spatariu


For some reason, the DOM was not updated right after it was shown so, a setTimeout e.g. 10 did the trick.

like image 20
lbrahim Avatar answered Nov 15 '22 16:11

lbrahim