Update 2016-06-27:而不是使用可观察的,使用
- @Abdulrahman在 comments 中推荐的BehaviorSubject,或者
- @Jason Goemaat在 comments 中推荐的ReplaySubject
Subject既是一个可观测值(因此我们可以对其使用subscribe()
)也是一个观察值(因此我们可以对其调用next()
以发出新值).我们利用这个特性.一个主题允许将值多播给许多观察者.我们不利用这个特性(我们只有一个观察者).
BehaviorSubject是主题的变体.它有"现值"的概念.我们利用这一点:每当我们创建ObservingComponent时,它都会自动从BehaviorSubject获取当前导航项值.
下面的代码和plunker use BehaviorSubject.
ReplaySubject是科目的另一个变体.如果要等到实际产生一个值,请使用ReplaySubject(1)
.BehaviorSubject需要初始值(将立即提供),而ReplaySubject则不需要.ReplaySubject将始终提供最新的值,但由于它没有必需的初始值,因此服务可以在返回其第一个值之前执行一些异步操作.它仍将在具有最新值的后续调用中立即触发.如果您只需要一个值,请在订阅上使用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
Original answer that uses an Observable:(与使用行为主题相比,它需要更多的代码和逻辑,所以我不推荐它,但它可能会很有启发性)
这是一个使用可观察instead of an EventEmitter的实现.与我的EventEmitter实现不同,此实现还将当前 Select 的navItem
存储在服务中,以便在创建观察组件时,它可以通过API调用navItem()
检索当前值,然后通过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 example,除了可观测外,它还使用Subject
.虽然示例是"父子通信",但同样的技术也适用于不相关的组件.