В целом, я пытаюсь добиться того, чтобы набор фильтров заголовка моей страницы контролировал входные параметры для нескольких страниц аналитики в моем приложении. Я инкапсулировал функциональность фильтров в службу Angular, которая предоставляет наблюдаемую информацию, которая генерируется при изменении фильтров. Я хочу, чтобы службы, использующие эти значения фильтров в запросах HttpClient, подписывались на изменения в фильтрах и повторно запускали свои запросы HttpClient при изменении фильтров (например, если изменяется диапазон дат, например, любые элементы на моей странице, которые управляются к этому диапазону дат обновляется автоматически).
Типичная служба данных в моем приложении будет выглядеть следующим образом. Кажется, то, что я пытаюсь сделать, должно быть достаточно простым, но я изо всех сил пытаюсь разобраться с библиотекой RxJS, чтобы объединить наблюдаемые так, как я стремлюсь.
export class DashboardDataService {
constructor(
private readonly http: HttpClient,
private readonly globalFiltersService: GlobalFiltersService
) { }
public getDashboard(): Observable<DashboardDto> {
const filtersSubscription = globalFiltersService.filters$.subscribe(...);
const observable = this.http.get<DashboardDto>(`${environment.apiBase}network/dashboard`, {
params: this.globalFiltersService.getHttpParams()
});
// TODO: when filtersSubscription receives new data, make observable re-run it's HTTP request and emit a new response
return observable; // Make this observable emit new data
}
}
Любая помощь будет принята с благодарностью. Я использую Angular 8 и RxJS 6, поэтому предпочтительнее использовать самый современный способ.
ОБНОВЛЕНИЕ: Рабочая реализация
export class GlobalFiltersService {
private readonly _httpParams$: BehaviorSubject<{ [param: string]: string | string[]; }>;
private start: Moment;
private end: Moment;
constructor() {
this._httpParams$ = new BehaviorSubject(this.getHttpParams());
}
public setDateFilter(start: Moment, end: Moment) {
this.start = start;
this.end = end;
this._httpParams$.next(this.getHttpParams());
}
public get httpParams$() {
return this._httpParams$.asObservable();
}
public getHttpParams() {
return {
start: this.start.toISOString(),
end: this.end.toISOString()
};
}
}
export class DashboardDataService {
private _dashboard$: Observable<DashboardDto>;
constructor(
private readonly http: HttpClient,
private readonly globalFiltersService: GlobalFiltersService
) { }
public getDashboard(): Observable<DashboardDto> {
if (!this._dashboard$) {
// Update the dashboard observable whenever global filters are changed
this._dashboard$ = this.globalFiltersService.httpParams$.pipe(
distinctUntilChanged(isEqual), // Lodash deep comparison. Only replay when filters actually change.
switchMap(params => this.http.get<DashboardDto>(`${environment.apiBase}network/dashboard`, { params })),
shareReplay(1),
take(1)
);
}
return this._dashboard$;
}
}
export class DashboardResolver implements Resolve<DashboardDto> {
constructor(private readonly dashboardDataService: DashboardDataService, private readonly router: Router) {}
public resolve(route: ActivatedRouteSnapshot, state: RouterStateSnapshot): Observable<DashboardDto> {
return this.dashboardDataService.getDashboard();
}
}