Angular2组件:无法在ngOnDestroy中发出@Output EventEmitter?

时间:2016-06-03 08:39:46

标签: angular

[angular2 rc1]

是否可以拥有这样的组件:

export class MyComp {
  @Output() myEvent = new EventEmitter(false)

  ngOnDestroy() {
    this.myEvent.emit('ngOnDestroy hook');
  }
}

并在父母身上抓住它:

<myComp (myEvent)="test($event)"></myComp>

这似乎是不可能的,但我想理解为什么?

我知道我可以使用服务来完成。

Plunker here

2 个答案:

答案 0 :(得分:5)

服务是一个很好的解决方案,但您想了解原因:

TL / DR说明:

订阅已取消订阅,在调用 ngOnDestroy()之前,通过角度取消订阅。这种自动化的发生是因为您订阅了模板,angular会解析模板,并且知道这一点。

更详细的解释:

Angular为每个组件生成一个工厂,此过程称为代码生成,由angular创建的工厂函数返回根据组件的元数据创建的唯一视图类型的实例,该类型继承 AppView 类。

组件实例的整个生命周期由视图管理。例如,更改检测以及生命周期钩子。

在调用 ngOnDestroy 生命周期钩子之前(通过组件的内部视图),会调用内部销毁函数,它会为您进行一些清理。 其中一项清理操作是取消订阅所有事件,例如点击,鼠标移动和自定义事件,它们是子组件中定义的@Output发射器。

这是静态完成的,这意味着代码生成器知道事件订阅,因此它添加了硬编码逻辑来删除它。 这是一件非常重要的事情,它可以节省大量样板代码并防止内存泄漏 - 框架可以为您清理。

注意角度可以做到这一点也很重要,因为它有很多关于发生了什么的元数据。 它知道它是订阅,因为它解析模板并找到一个事件表达式(例如:(click)="something()"),也因为 @Output 装饰器 MyComp

您可以在 AppView 类中清楚地看到逻辑 - LINK 每个视图都继承自 AppView ,并实现(以及其他)一个名为 destroyInternal 的函数。 命令是在销毁 destroyLocal()时调用(在AppView上定义),destroyLocal将清理所有订阅和一次性项目,然后它将调用 destroyInternal 然后,destroyInternal 会在您组件的实例上调用 ngOnDestroy()

解决方案:

现在,服务可能是一个很好的解决方案,但如果您了解正在发生的事情,您可以在没有外部服务的帮助下解决这个问题,这非常简单。 正如我们现在所知,angular将取消订阅模板中注册的订阅,如果我们手动注册(即:使用代码),我们将能够触发事件。

虽然简单,但它有一些样板,因为我们需要:

  • 我们需要获得对子组件的引用,我们将使用ViewChild
  • 我们需要在子组件实例上订阅该事件,但在ngAfterViewInit生命周期挂钩被触发后,我们可以
  • 我们需要在完成后取消订阅,这可以通过多种方式完成,最好的方法是完成 EventEmitter - 我们将在定义EventEmitter的组件中执行此操作只需致电myEvent.complete()即可。它会为我们处理一切。

这是销毁功能:

ngOnDestroy() {
  this.myEvent.emit('ngOnDestroy hook');
  this.myEvent.complete();
}

这是MyApp组件:

export class MyApp {
  displayComp = true

  @ViewChild('mycomp', {read: MyComp}) myComp: MyComp;
  constructor() {}

  ngAfterViewInit() {
    this.myComp.myEvent.subscribe( () => alert('myApp > receive event via MANUAL Subscription'));
  }

  test(e) {
    alert('myApp > receive event');
  }
}

这是一个工作的掠夺者 - LINK

更新:我刚刚在角度回购中注意到pending PR这个问题,现在12天仍然没有合并,合并社区贡献需要时间,所以希望它能在下一次登陆RC。

答案 1 :(得分:2)

这个PR应该解决这个问题。它会更改在分离事件之前调用ngOnDestroy()的行为。

https://github.com/angular/angular/pull/9946