41

I'm trying to access the nth child of a viewchildren querylist.

Below is my TS:

@ViewChildren(PopoverDirective) popovers: QueryList<PopoverDirective>;
console.log(this.popovers)

The console.log shows changes, first, last, length and _results.

How can I access the nth child (i.e., 3rd, instead of first)?

When I try to do this with _results (i.e., this.popovers._results[2]), I get an error.

Thank you.

user749798
  • 5,210
  • 10
  • 51
  • 85

3 Answers3

57

There are actually a couple of methods which you can access a particular inside you QueryLists

1st method: .filter()

You can also use .map and .reduce based on your preferences

// Since if you have 3 items in an array, the counting starts at 0, so 1 is the 2nd element
const elementTwo = this.popovers.filter((element, index) => index === 1);


// Or if you want to be specific based on the data inside the PopoverDirective
// and if that PopoverDirective has an @Input() name, you can access it by:
const elementTwo = this.popovers.filter((element, index) => element.name === 'John');

2nd method: .forEach()

// You can perform any action inside the .forEach() which you can readily access the element
this.popovers.forEach((element, index) => console.log(element));

3rd method: first and last

this.popovers.first         // This will give you the first element of the Popovers QueryList

this.popovers.last          // This will give the last element of the Popovers QueryList

Raw Array List: .toArray()

this.popovers.toArray();    // This will give you the list of popovers caught by your QueryList
KShewengger
  • 7,853
  • 3
  • 24
  • 36
  • 1
    Does the filter not return an array? –  Oct 02 '19 at 18:31
  • Hi @QianChen, the filter do returns an array. – KShewengger Oct 03 '19 at 10:18
  • Many thanks for clarifying. What if I want to iterate over a `QueryList`? Does that change anything? (I'm having trouble doing that now, but might've missed something obvious). – Crowdpleasr Oct 10 '19 at 17:48
  • 1
    Hi @Crowdpleasr, it's still the same you can apply those even if we were to querylist in element. Have attached Stackblitz demo for your reference - You can check the console. https://stackblitz.com/edit/ngx-viewchildren-querylist – KShewengger Oct 13 '19 at 02:21
  • `toArray()` creates a slice of the underlying querylist results everytime. Something to keep in mind for performance. – crush Dec 05 '20 at 16:18
  • IMO @rafi's answer is a better solution, since `find` returns _the one item at index_ instead of an array containing an item. – Peter Lillevold Jan 25 '22 at 15:04
  • @KShewengger Do you have an explanation on the reason why we shall not do `popovers[0]` on a `queryList` ? – Raphaël Balet Aug 28 '22 at 14:57
  • 1
    Hi @RaphaëlBalet, this may be late but to answer your question, accessing the query list immediately with popovers[0] will give you undefined. Instead, use popovers.toArray()[0] to access the element on the 0 index or use .first See the link for sample: https://stackblitz.com/edit/ngx-viewchildren-querylist-8bcbsa?devToolsHeight=33&file=src/app/app.component.ts – KShewengger Sep 07 '22 at 07:41
8

Accessing by index is possible through Find

  @ViewChildren(PopoverDirective) popovers: QueryList<PopoverDirective>;

  public getByIndex(x: number) {
    return this.popovers.find((_, i) => i == x)
  }
Rafi Henig
  • 5,950
  • 2
  • 16
  • 36
  • 3
    I actually found that this method is faster than calling `toArray()`. `toArray()` creates a slice of the underlying query list before accessing the index. Meanwhile, `find()` operates on the original underlying query list array. So, not only is it faster, but it will save some memory. – crush Dec 05 '20 at 16:27
5

you can use toArray() method and then you can access by index.

ABOS
  • 3,723
  • 3
  • 17
  • 23