Looping through Angular QueryList

Viewed 3110

So I want to get all the images in my component in an array, so I am using Angular's @ViewChildren which returns a QueryList of ElementRef:

@ViewChildren('img', { read: ElementRef }) images: QueryList<ElementRef>;

However, when ever I try to loop through the list am can't ever seem to get hold of the nativeElement. I am calling this in ngAfterViewInit()

this.images.forEach((img, index) => console.log("Image", img.nativeElement));

I don't get anything in the console.log, no error nothing.

This in turn does work:

console.log("this.images", this.images);

Below is an image of the log of console.log("this.images", this.images):

enter image description here

Here the html:

<div class="swiper-slide" *ngFor="let exhibit of exhibits; let i = index">
   <app-exhibit-images exhibitImagesId="{{ exhibit.fields.eventImages[0].sys.id }}" [eventPicturesStart]="eventPicturesStart" (sendEndEventPictures)="getEndEventImages($event)"></app-exhibit-images>
   <div id="exhibit-{{i}}"class="gallery__content" [ngClass]="{'show-event-pictures' : eventPicturesStart}">
      <div class="gallery__poster" [ngClass]="{'gallery-expand' : isGalleryExpanded }">
         <figure class="poster__image">
            <picture>
               <source srcset="{{ exhibit.fields.photo.fields.file.url }}" type="img/png">
               <img #img src="{{ exhibit.fields.photo.fields.file.url }}" alt="{{ exhibit.fields.photo.fields.description }}">
            </picture>
         </figure>
      </div>
      <div class="gallery__text" [ngClass]="{'gallery-expand' : isGalleryExpanded }">
         <button class="gallery-expand-button" (click)="expandGallery()"></button>
         <h2 class="gallery__heading">{{ exhibit.fields.title }}</h2>
         <h3 class="gallery__subheading">{{ exhibit.fields.subTitle }}</h3>
         <h4 class="gallery__artist">{{ exhibit.fields.artist }}</h4>
         <p class="gallery__description" *ngIf="exhibit.fields.description">{{ exhibit.fields.description }}</p>
      </div>
   </div>
</div>

What am I missing?

3 Answers

I ran into a similar issue with @ContentChildren. The solution was to subscribe to the changes observable of the QueryList.

Essentially, this will trigger whenever any of the state of the children changes. Normally this wouldn't be necessary but if your list of children is loaded in via a GET, this ensures the QueryList is data is loaded before executing on it. Its important to note the subscription will fire again whenever the any of the children's content changes.

@ContentChildren(forwardRef(() => ChildComponent), { descendants: true })
private children: QueryList<ChildComponent>;

ngAfterContentInit() {
    // subscribe to changes
    this.children.changes.subscribe(children => {
        children.forEach(child => {
            // do something with each child...
        });
    });
}

As @Jakopo Sciampi already mentioned a possibility is also to use the .toArray() function on the QueryList.

this.images.toArray().forEach((img, index) => {
            console.log('Image', img.nativeElement);
        });

Just make sure that you don't call the command to early => there will be no elements => the loop is not excecuted.

Don't call your loop in ngAfterViewInit, use ngAfterViewChecked instead. This will be triggered AFTER your child components are checked.

See lifecycle-hooks

Related