【问题标题】:How do I inject a parent component into a child component?如何将父组件注入子组件?
【发布时间】:2016-04-05 01:59:04
【问题描述】:

我正在尝试将父组件注入子组件。我认为这很简单——只需在孩子的constructor() 中指定/注入父组件:

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

我收到以下错误:

异常:无法解析 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) {}
}

应用组件:

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

【问题讨论】:

  • 马克,问题是当你从 A 导入 B 时,同时你从 B 导入 A 会创建一个循环依赖(不能更深入地讨论这个主题)。仅使用一个包含子组件和父组件的文件检查此plnkr
  • 感谢@EricMartinez,感谢您提供的所有其他 Angular2 cmets 以及关于 SO 的回答。我从你身上学到了很多。
  • 我想在上面的评论中修改一个字。它实际上是一个循环引用(不知道它是否相同,反正......)。我前段时间在 TypeScript 聊天室问过同样的事情,我得到了答案:You can check it here
  • 不客气@MarkRajcok 并感谢您的话,我真的很感激,很高兴知道我提供了帮助。我真的很想请您添加一个答案(如果您发现有关此主题的更多信息)来解释此问题。看到有另一个用户拥有same issue。回答这个和那个会很有帮助。
  • @EricMartinez,我看了你提到的另一个问题。它看起来不同(错误也不同)——每个组件的模板使用另一个组件。我没有那个答案。 (就我而言,我只希望注入父级,以便子级可以调用父级上的方法。)

标签: angular angular2-di


【解决方案1】:

请参阅@EricMartinez 的comment 以获得答案。当 A 导入 B 和 B 导入 A 时,问题似乎是循环引用。

这是一个plunker,它使用两个文件而不是Eric's plunker 中的一个文件。

与我原来的 plunker 的唯一变化是 ChildComponent:

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

我不确定这是否消除了循环引用,因为 A 和 B 仍在相互导入,但它似乎有效。

另见https://github.com/angular/angular/issues/3216,其中 Miško 指出:

这个 [使用 forwardRef() 的非用户友好声明] 是 JS 的限制以及函数声明如何被提升。每当您有循环依赖时,您都需要forwardRef :-( 我只是看不到它周围的地方。

我认为您不应该处于父母需要了解孩子而孩子需要了解父母的情况。 @Query 应该处理大部分用例。

很抱歉,虽然我同意这在极少数情况下会很痛苦,但我看不出有什么出路,因此这个问题不可行,将关闭。

嗯...我尝试注入父母的原因是因为我看到了孩子与父母交流的两种方式:

  1. 子级定义输出属性并发出事件,父级订阅这些事件
  2. 子级注入父级(例如,Pane 可能会注入 Tabs),然后可以调用父级上的方法

我试图确定何时使用每种方法。 Miško 听起来像 2. 应该很少见。

更新:我在考虑这个问题... 1. 更好,因为孩子和父母之间的耦合更少。 1. 孩子不需要知道(也可能不应该知道)父母的公共 API/接口。
在相反的方向(例如,父级使用@ViewChild@Query 现在已弃用)来获取对子级的引用,然后在子级上调用方法),耦合很好,因为父级正在使用子组件,所以它需要知道子组件的公共API/接口:即输入输出属性和公共方法。

【讨论】:

  • 是的,你是对的,但现在你的问题与此无关(也许使用 循环依赖 是一个错误)。您的问题是您有一个 循环引用 (看起来它们是不同的东西)。因此,当您执行import {A} from 'B'import {B} from 'A' 时,您就有了一个循环引用。这就是我在 plnkr 中删除它的原因。
  • @EricMartinez,我有点困惑。我最新的plunk 仍然有一个循环引用(对吗?),但它有效。使用@InjectforwardRef() 似乎可以解决循环引用问题。还有比这更多的吗?
  • 天哪……它有效!我不知道,实际上我不知道forwardRef 可以使用两个不同的文件来解决这个问题......这确实是一个很好的发现。我必须为我迄今为止所说的一切感到后悔。谢谢你开导我!你是对的,所以别迷茫,我错了!
  • 如何将 添加到子组件模板中?
  • @BenjaminMcFerren,我不建议这样做,因为您可能会陷入无限循环。我相信孩子应该(在极少数情况下)获得对父组件的引用的唯一原因是在父组件上调用公共方法/API。
【解决方案2】:

您可以像这样简单地使用@Host 装饰器:

import {Component, Host} from 'angular2/core';
// ....
constructor(@Host() private app: AppComponent)

【讨论】:

  • 我使用了@Host,但它不起作用;会否决你的答案,但在某些情况下它可能有效。因此,请详细说明为什么以及何时会起作用。
  • 您的具体情况是什么?
  • 这会注入宿主组件本身,而不是渲染实际组件的父组件
  • 上面的例子是专门注入 AppComponent @Host 会遍历视图提供者并注入最接近的匹配,所以在这种情况下,我们总是会得到AppComponent,因为您可以使用 @SkipeSelf 装饰器跳过组件本身
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 2016-06-12
  • 2016-05-15
  • 1970-01-01
  • 2017-05-18
  • 1970-01-01
  • 2020-01-06
  • 1970-01-01
相关资源
最近更新 更多