注入与子组件相同类型的父组件

时间:2016-02-29 19:02:55

标签: dependency-injection angular

在Angular 2中,子组件可以通过构造函数参数获取其父组件。例如:

@Component({...})
export class ParentComponent {
  ...
}

@Component({...})
export class ChildComponent {
  constructor(private parent: ParentComponent) { }
  ...
}

只要父母和孩子的类型不同,这种方法很有效。

然而,另一个典型用例是树结构,其中每个树节点显示为单独的组件。如果每个树节点组件都应该有权访问其父节点,我们该怎么办?我试过这个:

@Component({...})
export class TreeNodeComponent {
  constructor(private parent: TreeNodeComponent) { }
...
}

但是由于以下运行时异常而失败:

EXCEPTION: Cannot instantiate cyclic dependency!

我想原因是Angular 2注入组件本身而不是其父组件。

即使它们属于同一类型,我如何告诉angular注入一个组件的父组件?

Plunker https://plnkr.co/edit/ddvupV?p=preview

3 个答案:

答案 0 :(得分:20)

这种方式正在运作

constructor(@SkipSelf() @Host() @Optional() parent: TreeNodeComponent) {}

Plunker

  • @SkipSelf()如果请求TreeNodeComponent则不会自行注入
  • @Host()看起来不比主持人元素
  • @Optional() ??根节点
  • 没有父TreeNodeComponent

另见http://blog.thoughtram.io/angular/2015/08/20/host-and-visibility-in-angular-2-dependency-injection.html

答案 1 :(得分:0)

Angular2查看提供者的当前注入器。在您的情况下,TreeNodeComponent对应于组件本身。

父组件实例位于父注入器中。

我认为你可以尝试注入一个Injector类来访问父注入器,然后获取父组件的实例。这样的事情:

@Component({
  (...)
})
export class TreeNodeComponent {
  constructor(injector:Injector) {
    let parentInjector = injector.parent;
    let parent = patentInjector.get(TreeNodeComponent);
  }
}

有关Injector类的文档,请参阅此链接:

那就是说,我认为Gunter关于绑定和共享服务的评论特别相关......

答案 2 :(得分:0)

感谢Günther,这篇文章已经解决了。但是,我想根据我得到的架构反馈进行跟进。

首先:我完全同意TreeNodeComponent用例示例是反模式。像树这样的数据驱动组件应该通过数据绑定来控制。我为这种反模式道歉。

但是,我的实际用例(解释起来比较复杂)是我想开发一个高级下拉菜单。要求:

  • 下拉列表应具有任意数量的级别(菜单,子菜单,子菜单等)
  • 下拉列表是在设计时定义的 - 其内容不是基于动态数据。
  • 应该可以将事件处理程序(_)=附加到每个下拉项目。
  • 应该可以在下拉列表中插入自定义控件组件。

用法示例:

<dropdown label="Actions">
  <dropdown-item label="Action 1" (click)="action1()"></dropdown-item>
  <dropdown-item label="Action 2" (click)="action2()"></dropdown-item>
  <dropdown-item label="Submenu">
    <dropdown-item label="Action 3.1" (click)="action31()"></dropdown-item>
    <dropdown-item label="Action 3.2">
      <dropdown-slider (change)="changeHandler()"></dropdown-slider>
    </dropdown-item>
    <dropdown-item label="Submenu">
      <dropdown-item label="Action 3.3.1" (click)="action331()"></dropdown-item>
      <dropdown-item label="Action 3.3.2" (click)="action332()"></dropdown-item>
    </dropdown-item>  
  </dropdown-item>  
</dropdown>    

我的考虑是使用数据绑定很难实现。能够绑定事件处理程序并以这种方式包含自定义组件非常实用。

但我可能错了!对此非常欢迎!