Karl Dall
Karl Dall

Reputation: 31

Angular 5: Getting a QueryList for all ContentChildren (even the ones in sub components)

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

Answers (2)

waterplea
waterplea

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

Karl Dall
Karl Dall

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

Related Questions