Angular2のサービスのイベントをサブスクライブする方法?


112

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にイベントをサブスクライブさせるにはどうすればよいですか?

On 2.0.0-alpha.28を使用しています

編集:実際に機能するように「動作例」を変更したので、機能していない部分に焦点を合わせることができます;)

コード例:http : //plnkr.co/edit/m1x62WoCHpKtx0uLNsIv


1
サービスはコンポーネントに密​​接に結合しているため、サービスはコンポーネントに代わってイベントを発行してはならないため、これは設計上の問題になる可能性があります。たとえば、コンポーネントのインスタンスが複数ある場合、それらはすべてその場合にイベントを発行する必要がありますか?
Angular University

@jhadesdev読みました。ソリューションを再設計したので、サービスは結果を出力する必要がなくなりました。いくつかのデザインは、イベントを発生させることができることからメリットがあると思います-それがどのような「サービス」であるかによって異なります...
PerHornshøj-Schierbeck15年

一つの方法は、コンポーネントではなく、サービスのイベント・エミッターを作成し、サービスの引数としてイベント・エミッターを渡す持っているかもしれない
角度大学

回答:


135

更新:私は、EventEmitterではなくBehaviorSubjectまたはObservableを使用してこの問題を解決するより良い/適切な方法を見つけました。この回答をご覧ください:https : //stackoverflow.com/a/35568924/215945

また、Angularのドキュメントに、件名を使用するクックブックの例が追加されました


元の/古い/間違った答え:繰り返しますが、サービスでEventEmitterを使用しないください。それはアンチパターンです。

beta.1を使用しています... NavServiceにはEventEmiterが含まれています。コンポーネントナビゲーションはサービスを介してイベントを発行し、コンポーネント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 2016年

5
@ asubanovsky、plunkerでNavServiceを注入するのはブートストラップ(つまり、ルートコンポーネント)レベルだけなので、アプリ全体のサービスのインスタンスは1つだけです。あなたはそれを他の場所に注入していproviders: [NavService]ますか?その場合、サービスの複数のインスタンスを取得します。
Mark Rajcok

どうもありがとうございました。私の期待通りに動作しています。これで、ブートストラップレベルとコンポーネントレベルでのプロバイダーの注入の違いがわかりました。
asubanovsky 2016年

この投稿は、私が「それを取得する」ことができなくなった状態に大幅に変更されました。EventEmitterを返すサービス.getNavChangeEmitter()でメソッドを呼び出すと、navChangeに直接サブスクライブするのとなぜ違うのですか?
パーHornshøj-Schierbeck

@PerHornshøj-Schierbeck、私はメソッドgetNavChangeEmitter()を使用して、EventEmitterがサービス内で使用されているという事実を隠しました。メソッドのユーザーは、返されたオブジェクトにメソッドがあると想定できますsubscribe()。メソッドを使用することで、EventEmitterをSubjectまたはObservableに簡単に変更できます。これは、EventEmitterをOutputプロパティにのみ使用する必要があることを学習したためです。適切な方法は、Subject、BehaviorSubject、またはObservableを使用することであり、通常はこれらを直接サブスクライブするため、getNavChangeEmitter()メソッドは不要になります。
Mark Rajcok

6

alpha 28を使用して、eventEmitter.toRx().subscribe(..)メソッドを介してプログラムでイベントエミッターにサブスクライブしました。直感的ではないため、将来のリリースで変更される可能性があります。


1
おそらくこの投稿に出くわした場合に使用できる簡単な例を提供しますか?それは私がbtwを
投票し

2
なぜ反対票が投じられたのかわからない、それは確かに機能する。簡単に言えば、イベントエミッターの「クリック」をサブスクライブするには、次を使用します click.toRx().subscribe(your_callback_function)
Runeboy

実際の例がないため、反対票が投じられた可能性があると思いますか?構文をよりよく表示するために、pluncker / jsfiddleフィドルへのリンクまたはコードの行さえあれば、賛成票に値し、おそらく受け入れられる回答になると思います;)
PerHornshøj-Schierbeck15年

例外:ReferenceError:クリックが定義されていません@Runeboyソリューションのplnkrを提供できますか?
ベンジャミンマクフェレン2015年

それが機能するためには、クリックと呼ばれるEventEmitterを定義する必要があります
Mazen Elkashef
弊社のサイトを使用することにより、あなたは弊社のクッキーポリシーおよびプライバシーポリシーを読み、理解したものとみなされます。
Licensed under cc by-sa 3.0 with attribution required.