Reputation: 31
I have the following html structure where foo
and bar
are two directives and baz
is a custom component.
<div foo>
<div bar></div>
<baz><baz>
<baz><baz>
</div>
The html of the baz
-component looks something like ...
<div bar>Yada Yada Yada</div>
... and the foo
-directive looks something like this:
// ...
@Directive({
selector: '[foo]'
})
export class FooDirective implements AfterContentInit {
@ContentChildren(BarDirective)
m_bars: QueryList<BarDirective>;
public ngAfterContentInit(): void {
console.log('barCount:', this.m_bars.length);
}
}
The problem I experience is that the length of m_bars
inside the FooDirective
is 1. It only contains the div
that is a direct child of <div foo>
. I however expected this number to be 3 (the one direct child of <div foo>
and the other div
's inside the two baz
-components).
Why is that so and how can this problem be solved - if it can be solved at all?
Edit 1:
Changing the ContentChildren
decorator to
@ContentChildren(BarDirective, { descendants: true })
m_bars: QueryList<BarDirective>;
doesn't have any effect at all.
Upvotes: 2
Views: 6908
Reputation: 3641
Check this StackBlitz out (watch for console output): https://stackblitz.com/edit/angular-h7ybb3
You would have to chain that through outputs. QueryList has an Observable for changes, you could try using it as the output. Something along those lines:
@ContentChildren() something: QueryList<Type>;
@Output() queryListChange = new EventEmitter();
ngOnInit() {
this.something.changes.subscribe(v => {
this.queryListChange.emit(v);
}
}
And in the upper component you would need to subscribe to this output:
(queryListChange)="onQueryListChange($event)"
And in onQueryListChange you would need to merge those items you received with component's own ViewChildren.
And pass it along the same way if more levels of nesting is required.
I don't know a way to merge QueryLists so I just got original array from them and merged those in my stackblitz.
Upvotes: 0
Reputation: 31
It's just not possible, which sucks. See https://github.com/angular/angular/issues/20810#issuecomment-401341413 for further information. I'll quote the tl;dr version for reference:
In short: we only query component's own content, not content coming from other templates. This makes sense since a template forms a namespace #foo in one template might mean one thing and completely different thing in another template. Names might be the same but meaning quite different.
Upvotes: 1