nuton nuton - 1 month ago 12
TypeScript Question

Can't get to @ViewChildren in parent component

I am trying to get control over the children instances of a component and can't go past an error. I am trying to follow along the answers from this issue.

The parent component

Sequence
contains children components of
SequenceStep
. The parent contains the following declaration:

@ViewChildren(SequenceStep) steps: QueryList<SequenceStep>;


then I am trying to do something about the children:

ngAfterViewInit() {
this.steps.changes.subscribe(steps => {
console.log(steps);
});
}


The error I'm getting is:


metadata_resolver.js:639 Uncaught Error: Can't construct a query for
the property "steps" of "Sequence" since the query selector wasn't
defined.


whereas both
Sequence
and
SequenceStep
components do have their selectors defined in their
@Component
decorators (
sequence
and
sequence-step
respectively).

What am I doing wrong here?

Answer

There are a few things

  • If you pass children from the outside, they are content not children. @ViewChild() only works for children added to the template of a component directly.

@ContentChildren() works on transcluded content:

@ContentChildren(TheChild) kids: QueryList<TheChild>;
  • this.kids.changes() only notifies about changes after the initialization. Therefore just access this.kids directly in ngAfterViewInit() and then subsribe to get notified about later changes

    ngAfterViewInit() { this.myKidsCount = this.kids.length; this.cdRef.detectChanges();

    this.kids.changes.subscribe(kids => { this.myKidsCount = kids.length; }); }

  • Angular doesn't like when change detection causes changes. ngAfterViewInit() is called by change detection, this is why `this.myKidsCount = this.kids.length causes an exception.

To work around I invoke change detection explicitly after changing the property myKidsCount:

constructor(private cdRef:ChangeDetectorRef){}

ngAfterViewInit() {
  this.myKidsCount = this.kids.length;
  this.cdRef.detectChanges();
}

Plunker example