Как добавить родительский компонент в дочерний компонент?
Я пытаюсь внедрить родительский компонент в дочерний компонент. Я думал, что это будет просто - просто укажите / введите родительский компонент в дочернем constructor()
:
constructor(private _parent:AppComponent) {} // child component constructor
Я получаю следующую ошибку:
ИСКЛЮЧЕНИЕ: не удается разрешить все параметры для ChildComponent(?). Убедитесь, что все они имеют действительный тип или аннотации.
Что мне не хватает?
ChildComponent:
import {Component} from 'angular2/core';
import {AppComponent} from './app.component';
@Component({
selector: 'child',
template: `<p>child</p>`
})
export class ChildComponent {
constructor(private _parent:AppComponent) {}
}
AppComponent:
import {Component} from 'angular2/core';
import {ChildComponent} from './child.component';
@Component({
selector: 'my-app',
template: `{{title}} <child></child>
`,
directives: [ChildComponent]
})
export class AppComponent {
title = "Angular 2 - inject parent";
constructor() { console.clear(); }
}
2 ответа
Смотрите комментарий @EricMartinez для ответа. Кажется, проблема в том, что A импортирует B, а B импортирует A.
Вот плункер, который использует два файла вместо одного файла, который есть у Эрика.
Единственное отличие от моего оригинального плункера - в ChildComponent:
import {Component, Inject, forwardRef} from 'angular2/core';
....
constructor(@Inject(forwardRef(() => AppComponent)) private _parent:AppComponent)
Я не знаю точно, устраняет ли это циклическую ссылку, так как A и B все еще импортируют друг друга, но это, кажется, работает.
Смотрите также https://github.com/angular/angular/issues/3216, где Мишко заявляет:
Это [не дружественное к пользователю объявление, использующее forwardRef()], является ограничением JS и способа поднятия объявлений функций. Всякий раз, когда у вас есть круговая зависимость, вам понадобится
forwardRef
:-(Я просто не вижу вокруг себя.Я бы сказал, что вы не должны находиться в ситуации, когда ваш родитель должен знать о детях, а дети должны знать о родителе.
@Query
следует позаботиться о большинстве случаев использования.Извините, но, хотя я согласен, что в некоторых редких случаях это является болью, я не вижу выхода из этого, и, следовательно, эта проблема не может быть предпринята, будет закрыта.
Хм... причина, по которой я попытался сделать инъекцию родителю, заключалась в том, что я вижу два способа общения ребенка с родителем:
- дочерний элемент определяет выходные свойства и испускает события, на которые родитель подписывается
- дочерний элемент вводит родительский элемент (например, Pane может вводить вкладки), а затем может вызывать методы родительского элемента.
И я пытался определить, когда использовать каждый подход. Мишко делает это звучит как 2. должно быть редким.
Обновление: я думал об этом еще немного... 1. лучше, потому что между ребенком и родителем меньше связей. С 1. ребенку не нужно знать (и, вероятно, не должен знать) публичный API/ интерфейс родителя.
В обратном направлении (например, родитель использует @ViewChild
(@Query
в настоящее время не рекомендуется), чтобы получить ссылку на дочерний элемент, а затем вызывает методы дочернего элемента), связь в порядке, поскольку родительский компонент использует дочерний компонент, поэтому ему необходимо знать открытый API/ интерфейс дочернего элемента: т.е. свойства ввода и вывода и публичные методы.
Вы можете просто использовать @Host decorator следующим образом:
import {Component, Host} from 'angular2/core';
....
constructor(@Host() private app: AppComponent)