我在Angular应用程序(calendarComponent)内有一个日历,该日历通过mongodb的firebase云函数(通过名为calendarService的服务)获取其条目。要创建一个新条目,我会弹出一个角形材质对话框(addEventComponent)。该对话框需要数据库中的一些数据才能正常工作。到目前为止,对话框组件从calendarService请求数据,每次我要添加条目时,该日历服务都会执行一个新的http请求。根据Firebase数据计划,除了会有明显的延迟外,还可能触发成本增加。 理想情况下,calendarComponent将从ngOnInit上的calendarService请求数据,并根据请求将其传递给addEventComponent,但这仅在单击新的Entry对话框时完成http请求时才有效。 我对angular和rxjs经验不足,无法以不难看的方式解决此问题。
我最初尝试的是这样的:
在 calendarComponent
内部requiredData: RequiredData[];
ngOnInit() {
this.calendarService.getRequiredData().subscribe(response => {
this.requiredData = response.data;
});
}
addNewEntry () {
const dialogData = this.requiredData;
const dialogRef = this.dialogModal.open(AddEventComponent, {
data: { requiredData: dialogData },
});
}
(CalendarService只是返回一个http.get()请求,所以我没有在这里写代码。)
只要http请求永久生效,它就可以很好地工作。作为一个临时解决方案,我像以前一样触发了http请求,但是将响应保存在calenderService中,并返回了一个可观察到的结果。看起来像这样:
在 calendarComponent
内部ngOnInit() {
this.calendarService.getRequiredData();
}
在 calendarService
内部private requiredData$ = new Subject<RequiredData>();
requiredData: RequiredData[];
getRequiredData () {
this.http.get<{ _msg: string, reqData: RequiredData[] }>(API_URL)
.subscribe(response => {
this.requiredData = response.reqData;
this.requiredData$.next([...this.requiredData]);
});
}
getReqData () {
return this.requiredData$.asObservable();
}
我的问题出现在 AddEventComponent
requiredData: RequiredData[];
ngOnInit() {
this.calendarService.getReqData().subscribe(response => {
this.useTheRequiredData(response);
});
}
上面的代码将不起作用,因为如果请求已完成,则订阅会触发。因此,我需要的是一种更聪明的方法来执行此操作,或者是一种代码来检查是否可观察到的已发出的值,如果没有,则等待第一次发出的值,然后触发后续功能。 Kinda喜欢以下内容,但工作量较小。
在 AddEventComponent
内部requiredData: RequiredData[];
ngOnInit() {
if (this.calendarService.requiredData) {
this.useTheRequiredData(this.calendarService.requiredData);
} else {
this.calendarService.getReqData().subscribe(response => {
this.useTheRequiredData(response);
});
}
}
我们非常感谢您的帮助。
似乎有效的是( AddEventComponent )
this.calendarService.requiredData
? this.useTheRequiredData(this.calendarService.requiredData)
: this.calendarService.getReqData().pipe(
take(1),
tap(response => {
this.useTheRequiredData(response);
})
).subscribe();
主要让我感到困惑的是使用纯管道(模板中的角过滤管道,而不是rxjs管道),并没有意识到那很长。
答案 0 :(得分:0)
您是否考虑过使用RxJS ReplaySubject
而不是常规的Subject
? ReplaySubject
将在订阅者订阅时向他们发出最新的值:
除了使用getter函数之外,您还可以将ReplaySubject
公开为只读属性,并在CalendarService
的构造函数中对其进行初始化:
private requiredDataObservable$: Observable<RequiredData[]>;
[...]
constructor(...) {
this.requiredDataObservable$ = this.requiredData$.asObservable();
}
我个人将$
后缀用于暴露的可观察对象,对于主题则使用不带后缀的相应名称,但这只是我惯用的约定:
/** data subject to propagate changes */
private data: ReplaySubject<T[]>;
/** data observable exposed for subscribers */
protected data$: Observable<T[]>;