28

I am newbie at Angular2. In my view I have few identical children that are generated in *ngFor.

<ngb-panel *ngFor="let client of clients" [title]="'Client #' + client.id">
    <template ngbPanelContent>
        <processing-item [client]="client"></processing-item>
    </template>
</ngb-panel>

I need to call methods of these components at parent element and find out the ViewChildren decorator and the code is:

@ViewChildren(ProcessingItemComponent) processingItems: QueryList<ProcessingItemComponent>;

Then I try to iterate them by forEach:

ngAfterViewInit() {
    this.processingItems.forEach(function (el) {
        console.log(el);
    });
}

But it does nothing. toArray() method called on QueryList returns empty array.

Any suggestions how can I get all children components at one time and call its methods?

Anna Ladyzhenskaya
  • 283
  • 1
  • 3
  • 5

2 Answers2

41

If clients is set from an async call (for example to the server) then the elements don't exist in ngAfterViewInit() yet.

You can use

ngAfterViewInit() {
  this.processingItems.changes.subscribe(() => {
    this.processingItems.toArray().forEach(el => {
        console.log(el);
    });
  });
}

See also https://angular.io/api/core/QueryList#changes

Günter Zöchbauer
  • 623,577
  • 216
  • 2,003
  • 1,567
1

I think you should be using the @ContentChildren attribute instead of the ViewChildren.

@ContentChildren( OptionComponent )
public Options: QueryList<OptionComponent>;
  • Could you elaborate why? – Stefan Falk Sep 10 '18 at 10:40
  • Sorry stefan, what I wanted to say will not fit into a comment so I have added it as an answer below – Matthew Parton Sep 12 '18 at 07:43
  • I am assuming from the code above in the original question that the user wishes to use a template syntax and content projection. I find in this case the ContentChildren works better and would return the items. You may also want to put the – Matthew Parton Sep 12 '18 at 07:57
  • This is actually not correct for this question. In the question she is creating the components 'in-place' in the same component that the `ViewChildren` is placed. So it's not injected content from a parent component - but she wants to get a reference to the list of children created *in that component* via ngFor. – Simon_Weaver Mar 02 '19 at 00:26
  • Simon_Weaver is correct, but upvoting because I had a similar issue of `.toArray()` returning empty. Gunter's solution worked, but my underlying problem was that the parent container was passing the elements and I was using ViewChildren. Switching to ContentChildren allowed me to remove the subscribe logic from Gunter's answer. – Kevin Jul 01 '19 at 19:09