I have a demo here
I'm trying to get the height of an element after it is added to the DOM with *ngIf
I'm trying to do this by using a setter on the @ViewChild, the setter should be called one the *ngIf becomes true.
In my example it only seems to work when the element has been added then removed (button is clicked twice).
How can I get this to work when the element is firsy shown.
I know I can do this with [hidden] instead of *ngIf but my actual code has a lot of elements that I dont want to put in the DOM at once
import { Component, Input, ElementRef, ViewChild } from '@angular/core';
@Component({
selector: 'child-comp',
templateUrl: './child.component.html'
})
export class ChildComponent{
@Input() parent: ElementRef;
private blockThree: ElementRef;
@ViewChild('blockThree') set content(content: ElementRef) {
this.blockThree = content;
}
showThree: boolean = false
blockHeightThree: number
constructor(){ }
showBlockThree(){
this.showThree = !this.showThree
this.blockHeightThree = this.blockThree.nativeElement.clientHeight;
console.log('element height '+this.blockHeightThree);
}
}
The Angular @ViewChild decorator is one of the first decorators that you will run into while learning Angular, as it's also one of the most commonly used decorators. This decorator has a lot of features: some of them might not be very well known but they are extremely useful.
The @ViewChild and @ViewChildren decorators in Angular provide access to child elements in the view DOM by setting up view queries. A view query is a requested reference to a child element within a component view which contains metadata of the element.
ViewChild is used to select an element from component's template while ContentChild is used to select projected content.
The ViewChild or ViewChildren decorators are used to Query and get the reference of the DOM element in the Component. ViewChild returns the first matching element and ViewChildren returns all the matching elements as a QueryList of items. We can use these references to manipulate element properties in the component.
The reason it only works second time is, that the this.showThree = !this.showThree
does not call the setter right away, because whole function finishes first, only then angular actually detects the changes and puts the element in place. It will work if you move the height reading logic into the setter.
That means you cannot read blockHeightThree
in the showBlockThree
function, because the block three simply is not there yet. But there is an inelegant solution to that. You can put setTimeout()
there so the height is read asnychronously. Maybe it would do what you need.
Working Demo
@ViewChild('blockThree') set content(content: ElementRef) {
console.log("block three", content)
this.blockThree = content;
if (this.blockThree) {
this.blockHeightThree = this.blockThree.nativeElement.clientHeight;
console.log(this.blockThree.nativeElement.clientHeight);
}
}
showBlockThree() {
this.showThree = !this.showThree
console.log('element height ' + this.blockHeightThree);
setTimeout(()=> console.log("async block three", this.blockHeightThree));
}
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With