2

Suppose in my angular code i have access to a html element by viewChild('someDiv') or constructor(private elem: ElementRef){}.Whenever my angular component gets loaded i want access to that elements some property so i can store it in variable.Ex- i want to get the elements width as soon as that component gets loaded so my code is

@ViewChild('someDiv') someDiv: ElementRef;
someDivWidth;
ngOnInit(){
 someDivWidth = this.someDiv.nativeElement.clientWidth;
}

and my html code

<div #someDiv>some text</div>

But this is giving error like nativeElement is undefined.So how can i solve this?My basic need is as soon as this component loads i want to set that div's width in variable without triggering any function.

Update:

So using constructor(private elem: ElementRef){} isn't giving any error and i can get access to width by

ngOnInit(){
 this.someDivWidth = this.elem.nativeElement.querySelector('.someCssSelector');
}

But suppose i have some products data which i am fetching from backend and storing in an array in ngOnInit lifecycle hook and in my template creating multiple div's depending upon the products data array using lifecycle hook.In that case if i want to get all the product div's currently i am doing like

products = [];
items;
ngOnInit(){
 this.productService.getProducts().subscribe(products => {
  this.products = products 
 })
 this.itmes = this.elem.nativeElement.querySelectorAll('.each-product');
 console.log(this.items)
}

this is giving me a empty nodeList.I thought at the time of setting this.items my products don't gets loaded from backend thats why its giving me empty array or nodeList but putting that last two lines in subscribe() like

ngOnInit(){
 this.productService.getProducts().subscribe(products => {
  this.products = products 
  this.itmes = this.elem.nativeElement.querySelectorAll('.each-product');
  console.log(this.items)
 })
}

and my html code is

<div>
 <div *ngFor='let product of products' class='each-product'>...</div>
</div>

is still giving me an empty array or nodelist.What to do??

sahil aktar
  • 101
  • 10
  • ViewChild is only accesible after ngAfterViewInit. if you want to acces in ngOnInit use `{static:true}`:https://stackoverflow.com/questions/56359504/how-should-i-use-the-new-static-option-for-viewchild-in-angular-8 – Eliseo Sep 27 '20 at 02:10

3 Answers3

3

You should do it in the ngAfterViewInit method of the angular life cycle.

 ngAfterViewInit(){
             this.someDivWidth = this.elem.nativeElement.querySelector('.someCssSelector');
    }
1

ngOnInit lifeCycle is invoked once when component instantiated and called right after the properties checked for the first time, and before its children checked.

If You want to be sure that view has been loaded (@ViewChild depends on view to be rendered) you should use ngAfterViewInit which is called after component view and it's children view are created and ready.

UPDATE: If you need to access viewChild in ngOnInit you have to set { static: true }

Saghi Shiri
  • 537
  • 5
  • 19
  • Ok i understanded that part but can you please tell me why i am getting an empty nodelist here in `this.itmes = this.elem.nativeElement.querySelectorAll('.each-product');` and what to do for solving that problem?? – sahil aktar Sep 27 '20 at 13:30
0

Angular uses its algorithms to detect changes in data and respond to the view. If you want to opreate the DOM after the request was completed, you may not be able to get it because the view hasn't been updated yet, and you can understand that Angular also needs time to update the view. Offer two solutions

  1. Use ChangeDetectorRef to perform change detection manually
  2. use setTimeout

stackblitz-demo

rofrol
  • 14,438
  • 7
  • 79
  • 77
fbfatboy
  • 371
  • 1
  • 6
  • Why i am still getting empty nodelist using ngAfterViewInit.Html code `
    ` and ts code `ngAfterViewInit() { console.log(this.elem.nativeElement.querySelectorAll('.slideshow-card')); }`
    – sahil aktar Sep 27 '20 at 12:37
  • I have updated the code above. You need to learn about async request and lifestyle of Angular. – fbfatboy Sep 27 '20 at 12:41
  • You need to make sure that the DOM is rendered by the end of the your request – fbfatboy Sep 27 '20 at 12:42
  • Is that code works for you??Because i am still getting empty nodeList after calling the backend in ngAfterViewInit and console loging the querySelectorAll() in the subscribe method. – sahil aktar Sep 27 '20 at 13:27
  • https://stackblitz.com/edit/angular-ivy-czs5mo?file=src/app/app.component.css ..check in the code if i don't callback the backend in both ngOnInit and ngAfterViewInit i am getting empty nodelist hence totalWidth is 0.In first ngOnInit i am calling backend and subscribing to it to set my items array and in ngAfterViewInit if i am working with the items related dom without calling and subscribing to the backend again i am getting empty nodelist..do i have to call the backend and subscribe both in ngOnInit and ngAfterViewInit?? – sahil aktar Sep 29 '20 at 04:57