Cập nhật 2016-06-27: thay vì sử dụng Đài quan sát, hãy sử dụng một trong hai
- một BehaviorSubject, theo khuyến nghị của @Abdulrahman trong một bình luận, hoặc
- một ReplaySubject, như được đề xuất bởi @Jason Goemaat trong một bình luận
Một Chủ đề vừa là một Quan sát (vì vậy chúng ta có thể subscribe()
đối với nó) và một Người quan sát (vì vậy chúng ta có thể gọi next()
nó để phát ra một giá trị mới). Chúng tôi khai thác tính năng này. Một Chủ đề cho phép các giá trị được phát đa hướng cho nhiều Người quan sát. Chúng tôi không khai thác tính năng này (chúng tôi chỉ có một Người quan sát).
BehaviorSubject là một biến thể của Chủ đề. Nó có khái niệm "giá trị hiện tại". Chúng tôi khai thác điều này: bất cứ khi nào chúng tôi tạo ra một ObservingComponent, nó sẽ tự động nhận được giá trị mục điều hướng hiện tại từ BehaviorSubject.
Mã dưới đây và plunker sử dụng BehaviorSubject.
ReplaySubject là một biến thể khác của Chủ đề. Nếu bạn muốn đợi cho đến khi một giá trị thực sự được sản xuất, hãy sử dụng ReplaySubject(1)
. Trong khi một BehaviorSubject yêu cầu một giá trị ban đầu (sẽ được cung cấp ngay lập tức), ReplaySubject thì không. ReplaySubject sẽ luôn cung cấp giá trị gần đây nhất, nhưng vì nó không có giá trị ban đầu bắt buộc, dịch vụ có thể thực hiện một số thao tác không đồng bộ trước khi trả về giá trị đầu tiên. Nó vẫn sẽ kích hoạt ngay lập tức các cuộc gọi tiếp theo với giá trị gần đây nhất. Nếu bạn chỉ muốn một giá trị, sử dụng first()
trên thuê bao. Bạn không phải hủy đăng ký nếu bạn sử dụng 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
Câu trả lời gốc sử dụng một Observable: (nó đòi hỏi nhiều mã và logic hơn so với sử dụng BehaviorSubject, vì vậy tôi không khuyên bạn nên dùng nó, nhưng nó có thể mang tính hướng dẫn)
Vì vậy, đây là một triển khai sử dụng một Observable thay vì EventEuctor . Không giống như triển khai EventEuctor của tôi, việc triển khai này cũng lưu trữ navItem
dịch vụ hiện được chọn trong dịch vụ, để khi một thành phần quan sát được tạo, nó có thể truy xuất giá trị hiện tại thông qua lệnh gọi API navItem()
và sau đó được thông báo về các thay đổi thông qua navChange$
Quan sát.
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
Xem thêm ví dụ về Sách tương tác thành phần , trong đó sử dụng Subject
thêm vào các vật quan sát. Mặc dù ví dụ là "giao tiếp giữa cha mẹ và con cái", kỹ thuật tương tự được áp dụng cho các thành phần không liên quan.