Comment injecter un composant parent dans un composant enfant?

J'essaie d'injecter un composant parent dans un composant enfant. Je pensais que ce serait simple-il suffit de spécifier / injecter le composant parent dans constructor() de l'enfant:

constructor(private _parent:AppComponent) {}   // child component constructor

Je reçois l'erreur suivante:

EXCEPTION: Impossible de résoudre tous les paramètres de ChildComponent(?). Assurez-vous qu'ils ont tous un type ou des annotations valides.

Que suis-je manquant?

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

27
demandé sur Mark Rajcok 2015-12-31 06:27:12

1 réponses

Voir le commentaire de @ EricMartinez pour la réponse. Le problème semble être une référence circulaire Lorsque a importe B et b importe A.

Voici un plunker qui utilise deux fichiers au lieu d'un seul fichier qui est dans Eric plunker.

Le seul changement de mon plunker d'origine est dans le ChildComponent:

import {Component, Inject, forwardRef} from 'angular2/core';
....
constructor(@Inject(forwardRef(() => AppComponent)) private _parent:AppComponent)

Je ne sais pas avec certitude si cela élimine la référence circulaire, puisque A et B s'importent toujours, mais il semble travail.

Voir aussi https://github.com/angular/angular/issues/3216, où Miško états:

Cette [déclaration non conviviale utilisant forwardRef ()] est une limitation de JS et comment les déclarations de fonction sont hissées. Chaque fois que vous avez une dépendance circulaire, vous aurez besoin de forwardRef: - (Je ne vois tout simplement pas autour d'elle.

Je dirais que vous ne devriez pas être dans une situation où votre parent a besoin de connaître les enfants et les enfants ont besoin de connaître parent. @Query devrait s'occuper de la plupart des cas d'utilisation.

Je suis désolé, mais si je suis d'accord c'est une douleur dans certains cas rares, je ne vois pas un moyen d'en sortir, et donc ce problème n'est pas exploitables, va fermer.

Hmm... la raison pour laquelle j'ai essayé d'injecter le parent était parce que je vois deux façons pour un enfant de communiquer avec un parent:

  1. l'enfant définit les propriétés de sortie et émet des événements auxquels le parent s'abonne
  2. l'enfant injecte le parent (par exemple, le volet peut injecter des onglets) et peut ensuite appeler des méthodes sur le parent

Et j'essayais de déterminer quand utiliser chaque approche. Miško fait sonner comme 2. ça devrait être rare.

Mise à jour: j'y pensais un peu plus... 1. c'est mieux parce qu'il y a moins de couplage entre l'enfant et le parent. Avec 1. l'enfant n'a pas besoin de connaître (et ne devrait probablement pas connaître) L'API/interface publique du parent.
dans le sens inverse (par exemple, le le parent utilise @ViewChild (@Query est maintenant obsolète) pour obtenir une référence à l'enfant, puis appelle des méthodes sur l'enfant), le couplage est correct, car le parent utilise le composant enfant, il doit donc connaître L'API/interface publique de l'enfant: c'est-à-dire les propriétés d'entrée et de sortie et les méthodes publiques.

34
répondu Mark Rajcok 2017-05-23 12:18:14