In ngAfterViewInit life cycle hook images of the dom gets loaded completely?

1k views Asked by At

So in my current project i am trying to create a products slider.For that to work correctly i need to get the the width of all the products so i can calculate the total width.Currently what i am doing is

 ngAfterViewInit(): void {
    this.service.getData().subscribe((items) => {
      for (let key in items) {
        this.items.push(items[key]);
      }
      this.cd.detectChanges();
      this.cards = this.elem.nativeElement.querySelectorAll('.card');
      console.log(this.cards); // In this log i am getting all the cards have the correct width
      this.cards.forEach((card) => {
        console.log(card.getBoundingClientRect());//But in this log widths are different
        this.totalWidth += card.clientWidth;
      });
      console.log(this.totalWidth);
    });
  }

In ngAfterViewInit after calling my backend and setting it to laocal variable i am manually running change Detection.After that if i am console logging i am getting nodelist with all the items have correct width.But if i try to loop over the nodelist for getting the totalwidth i am getting different values.Here in each card i am currently showing one image and one text.I am not setting the card's width to a fixed value , i am setting the image's height to a fixed value apply width corresponded to that height so image will be responsive.So my looping over nodelist giving me wrong width value until the image is the loaded from memory cache.So my guess is it takes certain time to get the image loaded and my card's width is depended upon the images width thats why i am getting wrong width values if i try to loop over the nodelist.But than why the width values are correct in the nodelist and why it changes if i try to loop over them?How should i solve this problem to get the totalwidth based upon each cards width as soon as my component gets loaded without using setTimeOut().

Here is demo stackblitz code - https://stackblitz.com/edit/angular-ivy-czs5mo?file=src/app/app.component.ts

1

There are 1 answers

0
Eliseo On BEST ANSWER

You need check, in yours images the event (load). Some like

<img src="https://picsum.photos/200/300" (load)="onLoad()"/>

count:number=0;
yet:boolean=false;
onLoad()
{
   count++;
   this.checkWidth()
}

ngAfterViewInit()
{
    this.yet=true;
    this.checkWidth()
}
this.checkWidth()
{
   if (this.yet && count==imagesLength)
   {
       ..do something..
   }
}

NOTE: instead use

//I don't like so much
this.elem.nativeElement.querySelectorAll('.card');

You can use a referenceVariable #card in .html and control the elements use ViewChildren

@ViewChildren('card') cards:QueryList<ElementRef>

And use

this.cards.forEach(x=>{
   const rect=x.nativeElement.getBoundingClientRect()
   console.log(rect)
   ...
})