如何在 Angular2 中订阅服务上的事件?

Posted

技术标签:

【中文标题】如何在 Angular2 中订阅服务上的事件?【英文标题】:How to subscribe to an event on a service in Angular2? 【发布时间】:2015-09-16 20:23:27 【问题描述】:

我知道如何使用 EventEmitter 引发事件。如果我有这样的组件,我还可以附加一个要调用的方法:

<component-with-event (myevent)="mymethod($event)" />

当我有这样的组件时,一切都很好。我将一些逻辑移到了服务中,我需要从服务内部引发一个事件。我所做的是:

export class MyService 
  myevent: EventEmitter = new EventEmitter();

  someMethodThatWillRaiseEvent() 
    this.myevent.next(data: 'fun');
  

我有一个组件需要根据此事件更新一些值,但我似乎无法使其工作。我尝试的是这样的:

//Annotations...
export class MyComponent 
  constructor(myService: MyService) 
    //myService is injected properly and i already use methods/shared data on this.
    myService.myevent.on(... // 'on' is not a method <-- not working
    myService.myevent.subscribe(.. // subscribe is not a method <-- not working
  

当引发事件的服务不是组件时,如何让 MyComponent 订阅事件?

我在 2.0.0-alpha.28

编辑:将我的“工作示例”修改为实际工作,因此可以将重点放在不工作的部分;)

示例代码: http://plnkr.co/edit/m1x62WoCHpKtx0uLNsIv

【问题讨论】:

这可能更多是设计问题,因为服务不应代表组件发出事件,因为这将服务与组件紧密耦合。例如,如果组件有多个实例,在这种情况下它们是否都应该发出事件? @jhadesdev 我读到你了。我确实重新设计了解决方案,因此服务不再需要发出结果。我仍然认为一些设计会从能够引发事件中受益——这取决于它是什么样的“服务”...... 一种方法是让组件创建事件发射器而不是服务,然后将事件发射器作为参数传递给服务 【参考方案1】:

更新:我找到了一种更好/更合适的方法来解决这个问题,使用 BehaviorSubject 或 Observable 而不是 EventEmitter。请看这个答案:https://***.com/a/35568924/215945

此外,Angular 文档现在有一个 cookbook example that uses a Subject。


原始/过时/错误答案:再次,don't use an EventEmitter in a service。这是一种反模式。

使用 beta.1... NavService 包含 EventEmiter。组件 Navigation 通过服务发出事件,组件 ObservingComponent 订阅事件。

nav.service.ts

import EventEmitter from 'angular2/core';
export class NavService 
  navchange: EventEmitter<number> = new EventEmitter();
  constructor() 
  emitNavChangeEvent(number) 
    this.navchange.emit(number);
  
  getNavChangeEmitter() 
    return this.navchange;
  

components.ts

import Component from 'angular2/core';
import NavService from '../services/NavService';

@Component(
  selector: 'obs-comp',
  template: `obs component, item: item`
)
export class ObservingComponent 
  item: number = 0;
  subscription: any;
  constructor(private navService:NavService) 
  ngOnInit() 
    this.subscription = this.navService.getNavChangeEmitter()
      .subscribe(item => this.selectedNavItem(item));
  
  selectedNavItem(item: number) 
    this.item = item;
  
  ngOnDestroy() 
    this.subscription.unsubscribe();
  


@Component(
  selector: 'my-nav',
  template:`
    <div class="nav-item" (click)="selectedNavItem(1)">nav 1 (click me)</div>
    <div class="nav-item" (click)="selectedNavItem(2)">nav 2 (click me)</div>
  `,
)
export class Navigation 
  item = 1;
  constructor(private navService:NavService) 
  selectedNavItem(item: number) 
    console.log('selected nav item ' + item);
    this.navService.emitNavChangeEvent(item);
  

Plunker

【讨论】:

我已经遵循了这个,但它只适用于课程本身。它不适用于另一个类(来自另一个文件)。似乎问题出在服务类实例中。有没有办法让服务类变成静态的? @asubanovsky,在plunker 中,我只在引导程序(即根组件)级别注入 NavService,因此整个应用程序应该只有一个服务实例。你是用providers: [NavService] 将它注入其他地方吗?如果是这样,您将获得该服务的多个实例。 非常感谢。它现在按我的预期工作。现在我了解了在引导级别和组件级别注入提供程序之间的区别。 这篇文章被严重更改为我不再“明白”的状态。为什么在服务 .getNavChangeEmitter() 上调用返回 EventEmitter 的方法与直接订阅 navChange 不同? @PerHornshøj-Schierbeck,我使用 getNavChangeEmitter() 方法来隐藏在服务内部使用 EventEmitter 的事实。该方法的用户可以假设返回的对象具有subscribe() 方法。通过使用方法,我们可以轻松地将 EventEmitter 更改为 Subject 或 Observable,这样会更好,因为我们现在已经了解到 EventEmitters 应该只用于输出属性。正确的方法是使用 Subject、BehaviorSubject 或 Observable,我们通常直接订阅这些,因此我们不再需要 getNavChangeEmitter() 方法。【参考方案2】:

使用 alpha 28,我通过 eventEmitter.toRx().subscribe(..) 方法以编程方式订阅事件发射器。由于它不直观,它可能会在未来的版本中发生变化。

【讨论】:

也许提供了一个简单的例子供人们偶然发现这篇文章时使用?顺便说一句,不是我投反对票;) 不知道为什么它被否决了,它确实有效。简单地说,订阅事件发射器“点击”,使用click.toRx().subscribe(your_callback_function) 我认为它可能被否决了,因为它缺乏一个有效的例子?我知道如果它有一个指向 pluncker/jsfiddle fiddle 的链接或者甚至是一些代码行来更好地显示语法,那将是值得一票的,也许是一个被接受的答案;) 我收到了异常:ReferenceError: click is not defined @Runeboy 您能否为您的解决方案提供一个 plnkr? 您需要定义一个名为 click 的 EventEmitter 才能工作

以上是关于如何在 Angular2 中订阅服务上的事件?的主要内容,如果未能解决你的问题,请参考以下文章

在 angular2 中的 ngOnInit 之后,在构造函数中订阅服务

具有多个订阅者的 Angular 2 Observable

Angular 2:从订阅 http.post 获得响应后如何调用函数

如何在 Angular2 上使用 onBlur 事件?

如何在 Flask Server 上的 Google Pubsub 订阅回调中屈服以进行流式传输

ReactiveX JS 和 TypeScript - 如何取消订阅?