如何在 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:从订阅 http.post 获得响应后如何调用函数