Use @ViewChildren/@ContentChildren in combination with router-outlet

There is an on ongoing discussion here about how ContentChildren works, and it is closely related to your problem.

And in this comment it is explained that:

In Angular content projection and queries it means "content as it was written in a template" and not "content as visible in the DOM"

and

The consequence of this mental model is that Angular only looks at the nodes that are children in a template (and not children in the rendered DOM).

Similar to the issue above, components activated via router-outlet are not considered as ViewChildren or ContentChildren. They are just DOM children, and that doesn't mean anything to angular in terms of View and Content queries. There is no way (as of today) that they an be queried with ViewChild or ViewChildren or ContentChild or ContentChildren

My suggestion to solve your issue is to use a combination of activate event and the component property of RouterOutlet to achieve the desired behavior. As such:

Define router-outlet as follows:

<router-outlet #myRouterOutlet="outlet" (activate)='onActivate()'></router-outlet>

And use it as follows:

@ViewChild("myRouterOutlet", { static: true }) routerOutlet: RouterOutlet;
nbViewChildren: number;
links = [];

onActivate(): void {
  setTimeout(() => {
    const ancList: QueryList<AnchorDirective> = (this.routerOutlet.component as any).children;

    this.nbViewChildren = ancList.length;
    this.links = ancList.map(anc => anc.anchorTitle);
  })
}

Here is a working demo with improved typing: https://stackblitz.com/edit/angular-lopyp1

Also note that setTimeout is required because onActivate is fired during routing where the component life cycle hasn't started or finished yet. setTimeout ensures that the component lifecycle has completed, and that the component and underlying queries are ready as well.


The (activate)="handleActivate($event)" option won't work, as the router-outlet elements won't have been initialized yet. The $event in that case is indeed the component instance, but it's not really helpful here

The ViewChildren, ContentChildren don't seem to work for router-outlet. I didn't think they would, but tested it a good bit with your StackBlitz demo

You'll have to use a service, which is the standard way of doing it, and by far the most flexible. You will be able to get around the ExpressionChangedAfterItHasBeenCheckedError with ChangeDetectorRef.detectChanges(), or better still, use a BehaviorSubject, and next the values from that. In your template subscribe using async pipe, and you won't get those errors