Angular2组件:无法在ngOnDestroy内发出@Output EventEmitter吗? [英] Angular2 component: impossible to emit an @Output EventEmitter inside ngOnDestroy?

查看:97
本文介绍了Angular2组件:无法在ngOnDestroy内发出@Output EventEmitter吗?的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

[angular2 rc1]

[angular2 rc1]

是否可能具有这样的组件:

Is it possible to have a component like this:

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

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

并将其捕获到父项中:

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

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

It seems to be impossible but I would like to understand why?

我知道我可以使用一项服务来进行浏览.

I know I can use a service to walk through.

在此处插入

推荐答案

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

A service is a good solution, but you wanted to understand why:

在调用ngOnDestroy()之前,按一定角度为您取消订阅.之所以会发生这种自动化,是因为您订阅了模板,对模板进行了角度分析并且知道足够的信息.

The subscription is unsubscribed for you, by angular before ngOnDestroy() is called. This automation happens because your subscribed on a template, angular parses the template and knows enough to do so.

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

Angular generates a factory for each component, this process is called Code generation and the factory function created by angular returns an instance of a unique View type created according to the metadata of your component, which inherits the AppView class.

组件实例的整个生命周期由视图管理.例如,更改检测和生命周期挂钩.

The whole lifecycle of a component instance is managed by the view. For example, change detection and of course lifecycle hooks.

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

Before the ngOnDestroy lifecycle hook is called (by the internal view of your component) an internal destruction function is called, it does some cleaning for you. One of cleaning operations is unsubscribing from all events such as click, mouse move and custom events which are @Output emitters defined in child components.

这是静态完成的,这意味着代码生成器了解事件订阅,因此它添加了硬编码逻辑以将其删除. 重要的是,这样可以节省大量样板代码并防止内存泄漏-框架会为您进行清理.

This is done statically, which means that the code generator knows about the event subscription and so it adds hardcoded logic to remove it. Its an important thing, this saves a lot of boilerplate code and prevent memory leaks - the framework cleans up for you.

还需要注意的是,角度可以做到这一点,因为它具有很多有关正在发生的事情的元数据. 它知道它是一个订阅,因为它解析 Template 并找到事件表达式(例如:(click)="something()"),并且还因为 MyComp中的 @Output 装饰器

It's also important to note that angular can do it because it has a lot of metadata about what's going on. It knows that its a subscriptions because it parses the Template and find an event expression (e.g: (click)="something()") and also because of the @Output decorator in MyComp

您可以在 AppView 类中非常清楚地看到逻辑-

You can see the logic quite clearly in the AppView class - LINK Every view inherits from AppView and implements (among other things) a function called destroyInternal. The order is that on destruction destroyLocal() is called (defined on AppView), destroyLocal will clean up all subscriptions and disposable items and then it will call destroyInternal, destroyInternal will then call ngOnDestroy() on your component's instance.

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

Now, services might be a good solution but if you understand what's going on you can solve this without the help of an external service, it very simple. As we now know, angular will unsubscribe from subscriptions registered in a template, if we register manually (i.e: using code) we will be able to fire the events.

虽然简单,但由于需要,它具有一些样板:

While simple, it has some boilerplate since we need to:

  • 我们需要引用我们的子组件,我们将使用ViewChild
  • 我们需要在子组件实例上订阅该事件,但是只有在触发ngAfterViewInit生命周期挂钩之后,我们才能这样做.
  • 完成后,我们需要退订,这可以通过几种方式完成,最好的方法是完成-我们将在定义EventEmitter的组件中进行以下操作:呼叫myEvent.complete().它将为我们处理一切.
  • We need to get a reference to our child component, we will use ViewChild
  • We need to subscribe to the event on our child component instance but we can do it only after the ngAfterViewInit lifecycle hook is fired.
  • We need to unsubscribe once we're done, this can be done in several ways, the best way is to complete the EventEmitter - we will do it in the component that defines the EventEmitter simply by call myEvent.complete(). It will dispose everything for us.

这是销毁功能:

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

Here is a working plunker - LINK

更新:我刚刚在角度仓库中注意到了待处理PR 的问题,现在还没有合并的12天,合并社区贡献需要花费时间,所以希望它能在下一个RC中登陆.

UPDATE: I just noticed a pending PR for this issue in the angular repo, it's 12 days now still not merged, it takes time to merge community contribution so lets hope it will land in the next RC.

这篇关于Angular2组件:无法在ngOnDestroy内发出@Output EventEmitter吗?的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆