Aktualizacja 27.06.2016: zamiast korzystać z Obserwowalnych, użyj jednego z nich
- BehaviorSubject, zgodnie z zaleceniem @Abdulrahman w komentarzu, lub
- a ReplaySubject, zgodnie z zaleceniem @Jason Goemaat w komentarzu
Dotyczy to zarówno Obserwowalne (tak, możemy subscribe()
do niego) i obserwatora (tak możemy nazwać next()
go, aby emitować nową wartość). Wykorzystujemy tę funkcję. Temat pozwala wartościom być multiemisją dla wielu obserwatorów. Nie wykorzystujemy tej funkcji (mamy tylko jednego Obserwatora).
BehaviorSubject to odmiana podmiotu. Ma pojęcie „bieżącej wartości”. Wykorzystujemy to: za każdym razem, gdy tworzymy ObservingComponent, automatycznie pobiera bieżącą wartość elementu nawigacyjnego z BehaviorSubject.
Poniższy kod i plunker używają BehaviorSubject.
ReplaySubject to kolejny wariant podmiotu. Jeśli chcesz poczekać, aż wartość zostanie faktycznie wygenerowana, użyj ReplaySubject(1)
. Podczas gdy BehaviorSubject wymaga wartości początkowej (która zostanie podana natychmiast), ReplaySubject nie. ReplaySubject zawsze zapewnia najnowszą wartość, ale ponieważ nie ma wymaganej wartości początkowej, usługa może wykonać operację asynchroniczną przed zwróceniem swojej pierwszej wartości. Nadal będzie uruchamiany natychmiast po kolejnych połączeniach o najnowszej wartości. Jeśli chcesz tylko jedną wartość, skorzystaj first()
z subskrypcji. Nie musisz rezygnować z subskrypcji, jeśli korzystasz 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
Oryginalna odpowiedź, która wykorzystuje Observable: (wymaga więcej kodu i logiki niż użycie BehaviorSubject, więc nie polecam, ale może być pouczająca)
Oto implementacja korzystająca z Observable zamiast EventEmitter . W przeciwieństwie do mojej implementacji EventEmitter, ta implementacja przechowuje również aktualnie wybrany navItem
w usłudze, dzięki czemu, gdy tworzony jest komponent obserwacyjny, może on pobierać bieżącą wartość za pośrednictwem wywołania API navItem()
, a następnie być powiadamiany o zmianach za pośrednictwem navChange$
Obserwowalnego.
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
Zobacz także przykład książki kucharskiej interakcji między komponentami , w której Subject
oprócz obserwowalności używa się dodatkowo. Chociaż przykładem jest „komunikacja rodziców i dzieci”, ta sama technika ma zastosowanie do niepowiązanych komponentów.