问题描述
更改第一个Observable上的数据时,应更新第二个Observable。
不幸的是,这无法正常工作。
这是主要的Observable(效果很好)
export class LocaleService {
locale$: Observable<string>;
constructor(private router: Router) {
this.locale$ = router.events.pipe(
filter(evnt => envt instanceof ActivationEnd),map((evnt: ActivationEnd) => evnt.snapshot.paramMap.get('locale')),shareReplay(1),);
}
}
这里是第二个Observable,应根据第一个Observable的值(如上所示)进行更新:
// This type is more complex,but made it simple for demonstrating the problem
interface ICountries { code: string; }
export class DataService {
countries$: Observable<ICountries>;
constructor(private http: HttpClient,private localService: LocaleService) {
this.localeService.locale$.subscribe(locale => {
// this is only here for debug purposes,showing it does change
console.log('changed locale',locale);
});
this.countries$ = localeService.locale$.pipe(
tap(locale => { console.log('http updated',locale); }),// called first time only,not on locale changes...
switchMap(locale => this.http.get<ICountries>(`http://localhost:8080/countries?lang=${locale}`)),);
}
}
如果需要的话,我使用countries$
的方式如下(再次简化以演示问题):
@Component({
template: `<ng-container *ngIf="countries$ | async as countries">{{ countries.code }}</ng-container>`,})
export class CountryComponent implements OnInit {
countries$: Observable<ICountries>;
constructor(private dataService: DataService) {
this.countries$ = dataService.countries$;
}
}
我已经为此苦苦挣扎了几天,在StackOverflow上寻找答案,在许多其他论坛上问他们,并询问更频繁使用Observables的朋友,但是我似乎无法解决这个问题。任何帮助将不胜感激!
解决方法
我不确定,但是您可以尝试将可观察对象分成两个不同的部分。目前,它像下面的单流
this.countries = localeService.locale$.pipe(
tap(locale => { console.log('http updated',locale); }),// called first time only,not on locale changes...
switchMap(locale => this.http.get<ICountries>(`http://localhost:8080/countries?lang=${locale}`)),shareReplay(1),tap(locale => { console.log('http updated',shareReplay(1)
);
这是我的建议。我已经使用ReplaySubject
和缓冲区1(与问题中的shareReplay
相同)将可观察到的流分为两个不同的流
LocaleService
export class LocaleService {
localeSource = new ReplaySubject<string>(1);
locale$ = this.localeSource.asObservable();
constructor(private router: Router) {
router.events.pipe(
filter(evnt => envt instanceof ActivationEnd),map((evnt: ActivationEnd) => evnt.snapshot.paramMap.get('locale'))
).subscribe(event => this.localeSource.next(event));
}
}
DataService
// This type is more complex,but made it simple for demonstrating the problem
interface ICountries { code: string; }
export class DataService {
countriesSource = new ReplaySubject<ICountries>(1);
countries$ = this.countriesSource.asObservable();
constructor(private http: HttpClient,private localeService: LocaleService) {
this.localeService.locale$.pipe(
tap(locale => { console.log('http updated',switchMap(locale => this.http.get<ICountries>(`http://localhost:8080/countries?lang=${locale}`))
).subscribe(countries => this.countriesSource.next(countries));
}
}
CountryComponent
@Component({
template: `<ng-container *ngIf="(countries$ | async) as countries">{{ countries?.code }}</ng-container>`,})
export class CountryComponent implements OnInit {
countries$: Observable<ICountries>;
constructor(private dataService: DataService) {
this.countries$ = this.dataService.countries$;
}
}