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

IT技术 javascript angular
2021-03-09 23:22:13

我知道如何使用 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

2个回答

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

此外,Angular 文档现在有一个使用 Subject食谱示例


原始/过时/错误答案:同样,不要在 service 中使用 EventEmitter那是一种反模式。

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

导航服务.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;
  }
}

组件.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

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

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

如果人们偶然发现这篇文章,也许可以提供一个简单的例子供他们使用?顺便说一句,这不是我在投票;)
2021-04-19 23:22:13
我认为它可能被否决了,因为它缺乏一个有效的例子?我知道如果它有一个指向 pluncker/jsfiddle 小提琴的链接,或者甚至是一些代码行来更好地显示语法,那将是值得的,也许是一个可以接受的答案;)
2021-04-23 23:22:13
我得到例外:ReferenceError:点击未定义@Runeboy 你能为你的解决方案提供一个 plnkr 吗?
2021-04-28 23:22:13
不知道为什么它被否决了,它肯定有效。简单地说,要订阅事件发射器“单击”,请使用 click.toRx().subscribe(your_callback_function)
2021-05-06 23:22:13
您需要定义一个名为 click 的 EventEmitter 才能使其工作
2021-05-06 23:22:13