1

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

sahil aktar
  • 101
  • 10
  • Why are you calling console.log(card.getBoundingClientRect()) but measuring the total width with clientWidth? Those would typically be different values – dockleryxk Oct 01 '20 at 19:48
  • Even if i measure with offsetwidth the value is different..but when the images loaded in memory cache or sometime later in any function i call the same steps both values are same..i am trying to get the total width by measuring each cards width. – sahil aktar Oct 01 '20 at 20:49
  • So you're saying you need to know how to wait until the images load to check? – dockleryxk Oct 01 '20 at 21:15
  • first of all i want to know is this behaviour happening because the image take time to load for that each cards width in the nodelist have different width(console.log(this.cards)) and the next line if i try to loop over nodelist and access each cards width are totally different value. And how i can i achieve like as soon as the component loaded and images rendered i can measure the totalwidth.I dont want to use setTimeOut() because we will never know how much will it take until we will get correct width values. – sahil aktar Oct 01 '20 at 22:23

1 Answers1

0

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)
   ...
})
Eliseo
  • 50,109
  • 4
  • 29
  • 67