检查Observable(http请求)是否返回了一个值,以及是否没有等待它?

时间:2019-02-03 20:37:40

标签: angular rxjs angular-material

我在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管道),并没有意识到那很长。

1 个答案:

答案 0 :(得分:0)

您是否考虑过使用RxJS ReplaySubject而不是常规的SubjectReplaySubject将在订阅者订阅时向他们发出最新的值:

https://medium.com/@luukgruijs/understanding-rxjs-behaviorsubject-replaysubject-and-asyncsubject-8cc061f1cfc0

除了使用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[]>;