アップデート2016-06-27: Observablesを使用する代わりに、どちらかを使用
- @Abdulrahmanがコメントで推奨するBehaviorSubject、または
- コメントで@Jason Goemaatが推奨するReplaySubject
件名は、観察可能(私達ができるので、両方であるsubscribe()
こと)とオブザーバー(私たちが呼び出すことができるように、next()
新しい価値を放出することで)。この機能を利用します。サブジェクトを使用すると、値を多数のオブザーバーにマルチキャストできます。この機能は利用していません(オブザーバーは1つだけです)。
BehaviorSubjectは、Subjectのバリアントです。「現在の価値」という概念があります。これを利用します。ObservingComponentを作成すると、BehaviorSubjectから現在のナビゲーションアイテムの値が自動的に取得されます。
以下のコードとプランカーはBehaviorSubjectを使用します。
ReplaySubjectは、Subjectの別のバリアントです。値が実際に生成されるまで待機する場合は、を使用しますReplaySubject(1)
。BehaviorSubjectには初期値が必要です(これはすぐに提供されます)が、ReplaySubjectでは必要ありません。ReplaySubjectは常に最新の値を提供しますが、必要な初期値がないため、サービスは最初の値を返す前に非同期操作を実行できます。それでも、最新の値を持つ後続の呼び出しですぐに起動します。1つの値だけが必要な場合first()
は、サブスクリプションで使用します。を使用している場合は、登録を解除する必要はありませんfirst()
。
import {Injectable} from '@angular/core'
import {BehaviorSubject} from 'rxjs/BehaviorSubject';
@Injectable()
export class NavService {
// Observable navItem source
private _navItemSource = new BehaviorSubject<number>(0);
// Observable navItem stream
navItem$ = this._navItemSource.asObservable();
// service command
changeNav(number) {
this._navItemSource.next(number);
}
}
import {Component} from '@angular/core';
import {NavService} from './nav.service';
import {Subscription} from 'rxjs/Subscription';
@Component({
selector: 'obs-comp',
template: `obs component, item: {{item}}`
})
export class ObservingComponent {
item: number;
subscription:Subscription;
constructor(private _navService:NavService) {}
ngOnInit() {
this.subscription = this._navService.navItem$
.subscribe(item => this.item = item)
}
ngOnDestroy() {
// prevent memory leak when component is destroyed
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.changeNav(item);
}
}
Plunker
Observableを使用する元の回答:(BehaviorSubjectを使用するよりも多くのコードとロジックが必要なため、お勧めしませんが、参考になるかもしれません)
したがって、EventEmitterの代わりに Observableを使用する実装があります。私のEventEmitter実装とは異なり、この実装は現在選択さnavItem
れているサービスも格納するため、監視コンポーネントが作成さnavItem()
れると、API呼び出しを介して現在の値を取得し、navChange$
Observableを介して変更を通知できます。
import {Observable} from 'rxjs/Observable';
import 'rxjs/add/operator/share';
import {Observer} from 'rxjs/Observer';
export class NavService {
private _navItem = 0;
navChange$: Observable<number>;
private _observer: Observer;
constructor() {
this.navChange$ = new Observable(observer =>
this._observer = observer).share();
// share() allows multiple subscribers
}
changeNav(number) {
this._navItem = number;
this._observer.next(number);
}
navItem() {
return this._navItem;
}
}
@Component({
selector: 'obs-comp',
template: `obs component, item: {{item}}`
})
export class ObservingComponent {
item: number;
subscription: any;
constructor(private _navService:NavService) {}
ngOnInit() {
this.item = this._navService.navItem();
this.subscription = this._navService.navChange$.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:number;
constructor(private _navService:NavService) {}
selectedNavItem(item: number) {
console.log('selected nav item ' + item);
this._navService.changeNav(item);
}
}
Plunker
オブザーバブルに加えてを使用するComponent Interaction Cookbookの例も参照してくださいSubject
。例は「親と子のコミュニケーション」ですが、同じ手法が無関係なコンポーネントにも適用できます。