46

@Component({
    selector: '.donation',
    template: `
    <figure id="donation" move>
        <img src="image/qrcode.png"/>
        <figcaption>
        Buy me a cup of coffee.
        </figcaption>
    </figure>
    `
})
export class DonationComponent{}

@Directive({
    selector: '[move]'
})
export class MoveDirective{}

Hey, I want to get the <figure id="donation"> element's width/height within MoveDirective and DonationComponent. I have read the documentation several times but still cannot find a way to this answer. Does somebody know this? Thanks a lot!

4 Answers 4

66

You can use ElementRef as shown below,

DEMO : https://plnkr.co/edit/XZwXEh9PZEEVJpe0BlYq?p=preview check browser's console.

import { Directive, Input, Output, ElementRef, Renderer } from '@angular/core';

@Directive({
  selector:"[move]",
  host:{
    '(click)':"show()"
  }
})

export class GetEleDirective{
  
  constructor(private el:ElementRef) { }

  show(){
    console.log(this.el.nativeElement);
    
    console.log('height---' + this.el.nativeElement.offsetHeight);  //<<<===here
    console.log('width---' + this.el.nativeElement.offsetWidth);    //<<<===here
  }
}

Same way you can use it within component itself wherever you need it.

Sign up to request clarification or add additional context in comments.

7 Comments

Thanks a lot,It works perfect!But I am still a little confused about why using offsetHeight but not the height property to get the element's height?
ElementRef has been marked as security risk: angular.io/docs/js/latest/api/core/index/ElementRef-class.html - is it still ok to use it?
@shiva there isn't a risk, since you are also extracting information from the DOM, not inserting dangerous elements.
What about the case if children of host element have bigger width or height than the host. How can we get correct width and height of host element?
@Simon_Weaver: Yes you can do it or you can use windows.resize() event also but google it so you will come to know more about it.
|
39

For a bit more flexibility than with micronyks answer, you can do it like that:

1. In your template, add #myIdentifier to the element you want to obtain the width from. Example:

<p #myIdentifier>
  my-component works!
</p>

2. In your controller, you can use this with @ViewChild('myIdentifier') to get the width:

import {AfterViewInit, Component, ElementRef, OnInit, ViewChild} from '@angular/core';

@Component({
  selector: 'app-my-component',
  templateUrl: './my-component.component.html',
  styleUrls: ['./my-component.component.scss']
})
export class MyComponentComponent implements AfterViewInit {

  constructor() { }

  ngAfterViewInit() {
    console.log(this.myIdentifier.nativeElement.offsetWidth);
  }

  @ViewChild('myIdentifier')
  myIdentifier: ElementRef;

}

Security

About the security risk with ElementRef, like this, there is none. There would be a risk, if you would modify the DOM using an ElementRef. But here you are only getting DOM Elements so there is no risk. A risky example of using ElementRef would be: this.myIdentifier.nativeElement.onclick = someFunctionDefinedBySomeUser;. Like this Angular doesn't get a chance to use its sanitisation mechanisms since someFunctionDefinedBySomeUser is inserted directly into the DOM, skipping the Angular sanitisation.

4 Comments

How does this handle resize events?
It doesn't, but you can add a @HostListener window:resize, see e.g. scotch.io/tutorials/…
tried to follow your example but "this.myIdentifier" returns undefined...
Try this link for resize event. npmjs.com/package/angular-resize-event
0

@ViewChild doesn't work for everybody- at least, not for me. I'm using Angular 9. What did work was using @ViewChildren:

@ViewChildren('myIdentifier')
myIdentifier: QueryList<ElementRef>;

ngAfterViewInit() {
  this.myIdentifier.changes.subscribe((identifiers) => {
    console.log("OFFSET WIDTH", identifiers.first.nativeElement.offsetWidth);
  });
}

3 Comments

@ViewChild works always, when you ask for the element, the element was in the app. If you has under a *ngIf="condition" and the condition is not fullfilled, Angular can found it. If your condition is false and makes the condition true but you don't wait Angular "repaint", Angular can not find it -typical you enclosed in a setTimeout() to give time Angular "repaint"-
@Eliseo ngAfterViewInit is run only once, if I use *ngIf to see if myIdentifier returns a truthy value, it will just return false, won't it? Should I place this condition in another lifecycle hook?
Lybelle, yes ngAfterViewInit is run only one. But ViewChild "check" if exist or not unless you use @ViewChild('...',{static:true}) -static true, makes Angular don't "check" the element-. But if you use @ViewChild() without "static:true" Angular "check if exist or not" the element (imagine like a @Input that can have two values "true/false"). So you can make some like: click(){this.condition=true;setTimeout(()=>{console.log(this.element.nativeElement.offsetWidth}). a little example in this stackblitz
0
const rowHeight = this.elRef.nativeElement.querySelector('.datagrid-table > .datagrid-row').getBoundingClientRect().height;

https://angular.io/guide/migration-renderer

Inspired by this getting 'nativeElement.querySelector is not a function' exception in Angular2

Comments

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.