Как добавить родительский компонент в дочерний компонент?

Я пытаюсь внедрить родительский компонент в дочерний компонент. Я думал, что это будет просто - просто укажите / введите родительский компонент в дочернем 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(); }
}

Plunker

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 следует позаботиться о большинстве случаев использования.

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

Хм... причина, по которой я попытался сделать инъекцию родителю, заключалась в том, что я вижу два способа общения ребенка с родителем:

  1. дочерний элемент определяет выходные свойства и испускает события, на которые родитель подписывается
  2. дочерний элемент вводит родительский элемент (например, Pane может вводить вкладки), а затем может вызывать методы родительского элемента.

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

Обновление: я думал об этом еще немного... 1. лучше, потому что между ребенком и родителем меньше связей. С 1. ребенку не нужно знать (и, вероятно, не должен знать) публичный API/ интерфейс родителя.
В обратном направлении (например, родитель использует @ViewChild (@Query в настоящее время не рекомендуется), чтобы получить ссылку на дочерний элемент, а затем вызывает методы дочернего элемента), связь в порядке, поскольку родительский компонент использует дочерний компонент, поэтому ему необходимо знать открытый API/ интерфейс дочернего элемента: т.е. свойства ввода и вывода и публичные методы.

Вы можете просто использовать @Host decorator следующим образом:

import {Component, Host} from 'angular2/core';
....
constructor(@Host() private app: AppComponent)
Другие вопросы по тегам