Подтвердить что ты не робот

@ContentChildren не заполняется

У меня есть три компонента: App, Parent и Child:

Компонент приложения

@Component({
    selector: 'app',
    directives: [Parent,Child],
    template: '<parent><child>hi</child><child>there</child></parent>'
})
export class AppComponent {
    constructor() {
    }
}

Родительский компонент

@Component({
    selector: 'parent',
    template: '<div><h1>Parent</h1><ng-content></ng-content></div>'
})
export class Parent {
    @ContentChildren(Child) children: QueryList<Child>;
    ngAfterContentInit() {
        console.log(this.children);
    }
}

Детский компонент

@Component({
    selector: 'child',
    template: '<div><h1>Child</h1></div>'
})
export class Child {
}

Как вы видите в родительском компоненте, я попытался использовать @ContentChildren, чтобы получить список дочерних компонентов, используя тип Child в качестве селектора. Однако, похоже, это не работает - список дочерних элементов контента всегда undefined.

В методе ngAfterContentInit() я ожидал, что дети содержимого будут заполнены.

Я что-то упустил?

[Обновление]

Таким образом, оказывается, что проблема существует, когда все три компонента находятся в одном файле (см. окно отладки консоли, в котором я выводил содержимое содержимого):

Демо-версия Plnkr

Если они находятся в отдельных файлах, проблема исчезает:

Демо-версия Plnkr

Как правило, я только размещал все компоненты в одном файле для обучения. Но мне это любопытно. Кто-нибудь знает, почему поведение отличается?

4b9b3361

Ответ 1

Вам нужно использовать forwardRef для сравнения классов, которые еще не определены. См. этот плунжер. Запомнить ES6 классы не подняты.

@Component({
    selector: 'parent',
    template: '<div><h1>Parent</h1><ng-content></ng-content></div>'
})
export class Parent {
    @ContentChildren(forwardRef(() => Child)) children; // <!- HERE

    ngAfterContentInit() {
        console.log(this.children);
        console.log(this.children.length);
    }
}

UPD Марк Райкок отметил отличную статью о прямых ссылках в angular2 (см. комментарий ниже). Должно читать: thinkram.io Переслать ссылки в Angular 2.

Ответ 2

Это также происходит, если ваш дочерний компонент ссылается на ваш родительский компонент в конструкторе; Angular не любит круговую ссылку!

Мне нужно было выбрать только один метод для parent-> дочернего взаимодействия: либо использовать ContentChildren либо использовать родительский компонент в дочернем constructor.

@Component()
export class Parent {
  @ContentChildren(Child)
  private children: QueryList<Child>;
}

@Component()
export class Child {
  constructor(
    // !! Remove the following line to make the ContentChildren "work" again.
    @Optional() parent: Parent
  ) { }
}

Ответ 3

Вам нужно добавить { descendants: true }, чтобы включить вложенных детей,

@Component({
    selector: 'parent',
    template: '<div><h1>Parent</h1><ng-content></ng-content></div>'
})
export class Parent {
    @ContentChildren(Child, { descendants: true }) children: QueryList<Child>;
    ngAfterContentInit() {
        console.log(this.children);
        console.log(this.children.length);
    }
}

потомки - верно, чтобы включить всех потомков, в противном случае включить только прямые дети.