1

I've managed to connect my QueryList object to an observable with this line of code:

this.data.currentArray.subscribe(array => this.array = array);

But when I was trying to iterate through it, for some reason I didn't get the up-to-date values. More specifically I've used console.log to check the values, and:

  • When I wrote console.log(this.array.toArray()); - I got the up-to-date value on the 0th index;

  • But when I wrote console.log(this.array.toArray()[0]); - I didn't.

Someone suggested that it's because toArray() creates a new object, and thus disconnects from the observable. But if that's the case, how come the console.log(this.array.toArray()); line got me the up-to-date value?

I tried the answers from QueryList changes subscribe does not work and How can I get children elements from QueryList in Angular 2?, but neither of them worked.

Brandon Taylor
  • 33,823
  • 15
  • 104
  • 144
librogil
  • 91
  • 1
  • 7
  • QueryList has a `forEach` method. It's unclear from your question what you're trying to accomplish. – Brandon Taylor Mar 17 '23 at 12:27
  • I wanna iterate through that message QueryList object. Something like that: `if (this.message.toArray()[i].isActive()) {`... I saw this code: `ngAfterContentInit() { // subscribe to changes this.children.changes.subscribe(children => { children.forEach(child => { // do something with each child... }); }); }` [here] (https://stackoverflow.com/questions/61629180/looping-through-angular-querylist), but I'm not sure how to complete it... – librogil Mar 17 '23 at 12:53

2 Answers2

0

You shouldn't need to use an Observable with a QueryList in order to get access to a particular element in the array.

Example:

// component used for ViewChildren

import { Component, Input } from '@angular/core';

@Component({
  selector: 'app-message',
  template: `Message: {{ status }}`
})
export class MessageComponent {

  @Input()
  status: boolean = false;

}
// parent component

import { AfterViewInit, Component, Input, ViewChildren } from '@angular/core';

import { MessageComponent } from './somewhere';

@Component({
  selector: 'app-parent',
  template: `
  <ul>
    <li *ngFor="let status of statuses">
      <app-message [status]="status"></app-message>
    </li>
  </ul>`
})
export class ParentComponent implements AfterViewInit {

  @ViewChildren(MessageComponent)
  messageComponents: QueryList<MessageComponent>;

  statuses: boolean[] = [false, true, true, false, true];

  ngAfterViewInit(): void {
    this.messageComponents.forEach(statusComponent => {
      console.log(statusComponent.status);

      // outputs:
      // false
      // (2) true
      // false
      // true
    });
  }

}

Elements of a QueryList are also accessible via their index using .get():

const messageComponent = this.messageComponents.get(0);

Either of these methods will get you access to the child element/component without having to use an Observable.

If you need to be notified of when a value changes in one of those view children, you can use an @Output from the child or you could use a service.

You can also subscribe to the QueryList's .changes() Observable to be notified when the collection changes. I commonly do this to know when the elements of a QueryList have finished rendering.

Hope that helps you out.

Brandon Taylor
  • 33,823
  • 15
  • 104
  • 144
  • thank you so much for your help. i'll try to upload my code to stackblitz to make it (hopefully) simpler to understand my problem... – librogil Mar 17 '23 at 15:43
  • i've managed to access to it with your code example, but it didn't solve the problem... the value i get (through forEach) - is not the up-to-date one... i think i might just give up and use setTimeout even though it's not ideal... :( – librogil Mar 17 '23 at 16:05
  • Not sure I entirely understand the problem you're facing. The QueryList will give you the component instances, through which you'll have access to all of their public properties and methods. What exactly are you trying to access on the child components that isn't "up to date"? – Brandon Taylor Mar 17 '23 at 16:14
  • I'm not sure I can explain it better at this point. I'll try to simplify the code in the next few days, and try some suggestions I was given, like yours... Hopefully in a few days I'll be in a better place, at least to explain my problem better :) – librogil Mar 17 '23 at 16:57
0

Way to access multiple element with same reference through ViewChildren in Angular

import {
  Component,
  ViewChildren,
  AfterViewInit,
  QueryList,
} from '@angular/core';

import { HelloComponent } from './hello.component';

@Component({
  selector: 'my-app',
  templateUrl: './app.component.html',
  styleUrls: ['./app.component.css'],
})
export class AppComponent implements AfterViewInit {
  name = 'Angular';

  @ViewChildren('pRef') pRef: QueryList<any>;

  ngAfterViewInit() {
    this.pRef.forEach((e) => console.log(e.nativeElement));
  }
}
<p #pRef *ngFor="let item of [1, 2, 3, 4]">HELLO {{ item }}</p>
Jerry
  • 1,005
  • 2
  • 13