If I add a content children to my component
@ContentChildren(RouterLink, { descendants: true })
links: QueryList<RouterLink>;
and have a template
<a [routerLink]="''">Link 1</a><br>
<a [routerLink]="''">Link 2</a><br>
<a [routerLink]="''">Link 3</a><br>
Number of links: {{links.length}}
Links length is always 0.
I have tried with a directive as well
@Directive({
selector: '[appRouterLinkWatch]'
})
export class RouterLinkWatchDirective implements AfterContentInit {
@ContentChildren(RouterLink, { descendants: true })
links: QueryList<RouterLink>;
constructor(@Optional() private link: RouterLink) {}
ngAfterContentInit() {
console.log(this.links.length, this.link);
}
}
Both the links content children and the link dependency are not populated. What am I doing wrong to get a list of router links in my component?
I have been looking at the sorce code for the routerLinkActive directive https://github.com/angular/angular/blob/master/packages/router/src/directives/router_link_active.ts I cannot see what I am doing differently.
I have a stack blitz here https://stackblitz.com/edit/angular-ivy-bvpyhd?file=src%2Fapp%2Fapp.component.html
It appears the RouterLink
directive utilizes two separate types internally.
RouterLink
and RouterLinkWithHref
routerLink
directly in componentIf we want to count the routerLinks
directly in the component, and expect no projected links, then we must use @ViewChildren()
rather than @ContentChildren()
.
@Component({...})
export class AppComponent implements AfterViewInit {
@ViewChildren(RouterLink) routeWithoutHref!: QueryList<RouterLink>;
@ViewChildren(RouterLinkWithHref) routeWithHref!: QueryList<RouterLinkWithHref>;
ngAfterViewInit() {
console.log(this.routeWithHref.length); // expect 2
console.log(this.routeWithoutHref.length); // expect 1
}
}
<a routerLink>link</a>
<a routerLink="a">link</a>
<div routerLink="b">link</div>
The above component produces a length of 2 for RouterLinkWithHref
and a length of 1 for RouterLink
from which I summize it depends on whether the RouterLink
is attached to an anchor or not.
Whether the directive has any input does not appear to bear any influence.
Much the same as before, except we now utilize ContentChildren
instead of ViewChildren
@Directive({selector: '[countRoutes]'})
export class RouteCountDirective implements AfterContentInit{
@ContentChildren(RouterLink, {descendants: true}) routerLinks!: QueryList<RouterLink>
@ContentChildren(RouterLinkWithHref, {descendants: true}) routerLinksWithHref!: QueryList<RouterLinkWithHref>
ngAfterContentInit() {
console.log(this.routerLinks.length) // 1
console.log(this.routerLinksWithHref.length) // 2
}
}
<div countRoutes>
<a routerLink>link</a>
<a routerLink="a">link</a>
<div routerLink="b">link</div>
</div>
Notice
When using the {descendants: true}
option for the ContentChildren
only routerLinks
nested inside the element on which the countRoutes
directive is attached will be selected.
<div countRoutes>
<a routerLink>Counted</a>
<a routerLink="a">Counted</a>
<div routerLink="b">Counted</div>
</div>
<a routerLink="c">Not Counted</a>