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

Posted

技术标签:

【中文标题】注入与子组件同类型的父组件【英文标题】:Inject parent component of the same type as child component 【发布时间】:2016-06-12 23:01:14 【问题描述】:

在 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

【问题讨论】:

为什么要注入父节点,为什么不直接使用数据绑定? 试试这个:***.com/questions/34540615/… 【参考方案1】:

这样就可以了

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

【讨论】:

她是个笨蛋:link。阅读 treenode.component 中的注释。 我理解您对策略的评论,我完全同意。在像这样的树结构的情况下,它会使用绑定。我的实际用例是不同的。我只是以树节点为例来说明核心挑战,因为树结构是一个众所周知的概念。 好的,找到了。我错过了@SkipSelf()(以及根节点所必需的@Optional() 如果这解决了您的问题,您是否介意接受表明您的问题已得到解答的答案(向上/向下投票按钮下方的白色复选标记)。谢谢。 从来不知道@SkipSelf()!谢谢@Gunter!我有 @Optional() 和 @Host() 但错过了这个重要的部分。【参考方案2】:

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

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

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

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

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

https://angular.io/docs/ts/latest/api/core/Injector-class.html

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

【讨论】:

【参考方案3】:

感谢 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>    

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

但我可能错了!非常欢迎对此提出任何意见!

【讨论】:

这看起来不像是一个答案。我认为编辑您的问题并在那里添加此内容会更好。 你为什么要注入父母?您想从父级访问哪些成员? 我需要注入父项,因为打开一个菜单项应该关闭所有同级项,以便同时打开一个“菜单路径”。为了实现这一点,我必须能够调用父组件。 您可以在&lt;child&gt; element for that and bind a method to it. 上使用@Output()` 为了将值从父级传递给子级,您添加一个@将 987654324@ 绑定到孩子并将其绑定为 &lt;child [someInputOnChild]="someValueFromParent"&gt; ,其中值可以是一切,甚至是函数。

以上是关于注入与子组件同类型的父组件的主要内容,如果未能解决你的问题,请参考以下文章

angularjs 自定义弹窗指令

ASP.NET Core 依赖注入错误:尝试激活时无法解析服务类型 - 调用视图组件时出现错误 [重复]

当父组件在其子组件中注入道具时,如何在 Typescript 中定义道具?

Springboot学习笔记-常用注入组件方式

@Autowired @Resource @Inject 自动注入

如何在 react.js 的父组件中检测子渲染