[angular2 rc1]
是否可以拥有这样的组件:
export class MyComp {
@Output() myEvent = new EventEmitter(false)
ngOnDestroy() {
this.myEvent.emit('ngOnDestroy hook');
}
}
并在父母身上抓住它:
<myComp (myEvent)="test($event)"></myComp>
这似乎是不可能的,但我想理解为什么?
我知道我可以使用服务来完成。
答案 0 :(得分:5)
服务是一个很好的解决方案,但您想了解原因:
订阅已取消订阅,在调用 ngOnDestroy()之前,通过角度取消订阅。这种自动化的发生是因为您订阅了模板,angular会解析模板,并且知道这一点。
Angular为每个组件生成一个工厂,此过程称为代码生成,由angular创建的工厂函数返回根据组件的元数据创建的唯一视图类型的实例,该类型继承 AppView 类。
组件实例的整个生命周期由视图管理。例如,更改检测以及生命周期钩子。
在调用 ngOnDestroy 生命周期钩子之前(通过组件的内部视图),会调用内部销毁函数,它会为您进行一些清理。 其中一项清理操作是取消订阅所有事件,例如点击,鼠标移动和自定义事件,它们是子组件中定义的@Output发射器。
这是静态完成的,这意味着代码生成器知道事件订阅,因此它添加了硬编码逻辑来删除它。 这是一件非常重要的事情,它可以节省大量样板代码并防止内存泄漏 - 框架可以为您清理。
注意角度可以做到这一点也很重要,因为它有很多关于发生了什么的元数据。
它知道它是订阅,因为它解析模板并找到一个事件表达式(例如:(click)="something()"
),也因为 @Output 装饰器 MyComp 强>
您可以在 AppView 类中清楚地看到逻辑 - LINK 每个视图都继承自 AppView ,并实现(以及其他)一个名为 destroyInternal 的函数。 命令是在销毁 destroyLocal()时调用(在AppView上定义),destroyLocal将清理所有订阅和一次性项目,然后它将调用 destroyInternal ,然后,destroyInternal 会在您组件的实例上调用 ngOnDestroy()。
现在,服务可能是一个很好的解决方案,但如果您了解正在发生的事情,您可以在没有外部服务的帮助下解决这个问题,这非常简单。 正如我们现在所知,angular将取消订阅模板中注册的订阅,如果我们手动注册(即:使用代码),我们将能够触发事件。
虽然简单,但它有一些样板,因为我们需要:
ngAfterViewInit
生命周期挂钩被触发后,我们可以 。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()
的行为。