Angular 5: Получение QueryList для всех ContentChildren (даже в подкомпонентах) - PullRequest
0 голосов
/ 05 июля 2018

У меня есть следующая HTML-структура, где foo и bar - две директивы, а baz - пользовательский компонент.

<div foo>
  <div bar></div>
  <baz><baz>
  <baz><baz>
</div>

HTML-код baz -компонента выглядит примерно так ...

<div bar>Yada Yada Yada</div>

... и директива foo выглядит примерно так:

// ...
@Directive({
  selector: '[foo]'
})
export class FooDirective implements AfterContentInit {

  @ContentChildren(BarDirective)
  m_bars: QueryList<BarDirective>;

  public ngAfterContentInit(): void {

    console.log('barCount:', this.m_bars.length);
  }
}

Проблема, с которой я сталкиваюсь, состоит в том, что длина m_bars внутри FooDirective равна 1. Она содержит только div, который является прямым потомком <div foo>. Однако я ожидал, что это число будет равно 3 (один прямой потомок <div foo>, а другой div - внутри двух baz -компонентов).

Почему это так и как можно решить эту проблему - если она вообще может быть решена?

Редактировать 1: Изменение декоратора ContentChildren на

@ContentChildren(BarDirective, { descendants: true })
m_bars: QueryList<BarDirective>;

вообще не имеет никакого эффекта.

Ответы [ 2 ]

0 голосов
/ 05 июля 2018

Это просто невозможно, что отстой. См. https://github.com/angular/angular/issues/20810#issuecomment-401341413 для получения дополнительной информации. Я приведу tl; dr версию для справки:

Короче говоря: мы запрашиваем только собственное содержимое компонента, а не содержимое других шаблонов. Это имеет смысл, так как шаблон образует пространство имен #foo в одном шаблоне, что может означать одно и совершенно другое в другом шаблоне. Имена могут быть одинаковыми, но означать совершенно разные.

0 голосов
/ 05 июля 2018

Проверьте это StackBlitz out (следите за выходом консоли): https://stackblitz.com/edit/angular-h7ybb3

Вы должны связать это через выходы. QueryList имеет Observable для изменений, вы можете попробовать использовать его в качестве вывода. Что-то в этом роде:

@ContentChildren() something: QueryList<Type>;

@Output() queryListChange = new EventEmitter();

ngOnInit() {
    this.something.changes.subscribe(v => {
        this.queryListChange.emit(v);
    }
}

А в верхнем компоненте вам нужно подписаться на этот вывод:

(queryListChange)="onQueryListChange($event)"

А в onQueryListChange вам необходимо объединить полученные элементы с собственными ViewChildren компонента.

И передать его таким же образом, если требуется больше уровней вложенности.

Я не знаю, как объединить QueryLists, поэтому я просто получил от них оригинальный массив и слил их в свой стек-блиц.

...