Angular和Firestore:异步获取Firebase数据

时间:2018-11-12 16:20:58

标签: angular firebase asynchronous google-cloud-firestore

很抱歉,如果标题有点错误,但是我在此处发布此问题的原因是因为我有点儿不知所措,无法在网上找到我要找的东西。我也不太清楚我要寻找什么。

因此,我有一个角度应用程序,并且正在使用Firestore作为数据库。因此,我正在使用这段代码将我的收藏集添加到服务中:

this.userAsteroid$ = this.afs.collection<UserAsteroid>(this.collection).valueChanges();

然后我在服务中有一个函数返回this.userAsteroid $。然后,在我的组件的ngOnInit中,有以下内容:

this.userAsteroid$ = this.userAsteroidService.getAsteroids();

this.userAsteroid$.subscribe(asteroids => {
  asteroids.forEach(document => {
    if (document.asteroidId == this.id && document.userId == this.user.uid) {
      this.hasAsteroid = true;
      console.log("test: ", this.hasAsteroid);
    }
    console.log(document);
  });
});

因此,基本上,我的组件是特定小行星的详细信息页面,并且当我的收藏集包含一个包含小行星ID和已登录用户的ID的文档时,我希望将bool hasAsteroid设置为true

这是组件的html

    <div [hidden]="loading">
  <div class="columns" *ngIf="!hasAsteroid && user">
    <div class="column">
        <button class="button is-primary is-outlined" type="button" (click)="addAsteroid(id)">Add to my asteroids</button>
    </div>
  </div>

现在,此方法有效,但仅当我重新加载页面时才有效,而当我导航至该页面时则无效。我怀疑这与以下事实有关:我使用的订阅函数不是异步的,因此有时在bool设为true之前会加载我的页面,然后使用该bool的* ngIf不会工作。

我尝试使用.pipe然后映射,就像处理从API接收的JSON数据一样,但是在这种情况下,它什么也没做。

在另一个组件中,我使用的是从服务到现在的相同功能,以获取一个用户已保存的所有小行星,如下所示:

getUserFeed() {
this.authService.userData$.subscribe(data => this.user = data);
this.userAsteroid$ = this.userAsteroidService.getAsteroids();

this.userAsteroid$.subscribe(asteroids => {
  asteroids.forEach(document => {
    if (document.userId == this.user.uid) {
      console.log(document.asteroidId);
      this.dataArray.push(document.asteroidId);
    }
  });
})}

如您所见,我会将用户保存的所有小行星ID推入数组,以便以后可以使用它们进行api调用。

我没有在这里写其余的代码,因为我知道由于该函数不异步而无法正常工作。

如果任何人都有解决方案,或者可以向我指出进行该工作所需的正确文档,我将非常感激。

编辑:

在课堂上进一步研究此问题之后,我解决了部分问题,并能够更准确地确定问题所在,但是问题仍然存在。在最初展示的两个函数中,我都有一部分使用此代码块

this.authService.userData$.subscribe(data => {
  this.user = data;

  this.userAsteroid$ = this.userAsteroidService.getAsteroids();

  this.userAsteroid$.subscribe(asteroids => {
    asteroids.forEach(document => {
      if (document.asteroidId == this.id && document.userId == this.user.uid) {
        this.hasAsteroid = true;
        console.log("test: ", this.hasAsteroid);
      }
      console.log(document);
    });
  });
});

基本上,我正在订阅authSerivce来确定我的用户,在该订阅中,我订阅了我的Firestore服务,然后执行了一些工作。

当我最初加载组件时,所有这些都有效。但是,我在路由中使用参数来处理“标签”。我在ngOnit中订阅了这些参数,因此当我单击导航中的链接时,我的页面将使用正确的参数更新组件。然后,在此订阅中,我想起了我的功能。

但是,当我回忆起该函数时,它仍将订阅用户,仍将从Firestore获取可观察对象,但不会再次订阅该可观察对象。基本上,当我调用该函数时,从此行开始的所有内容都无法正常工作

this.userAsteroid$.subscribe(asteroids => {

有人知道为什么吗?

2 个答案:

答案 0 :(得分:1)

如何将文档查找移到auth订阅中?

getUserFeed() {
  this.authService.userData$.subscribe(data => {
    this.user = data
    this.userAsteroid$.subscribe(asteroids => {
      asteroids.forEach(document => {
        if (document.userId == this.user.uid) {
          console.log(document.asteroidId);
          this.dataArray.push(document.asteroidId);
        }
      });
    })}
  });
  this.userAsteroid$ = this.userAsteroidService.getAsteroids();
}

通过这种方式,可以保证只有在userAsteroid$可用后才能建立this.user订阅。

如果您选择这条路线,则可能需要检测是否已经订阅this.userAsteriud$,并在这种情况下跳过重新订阅。

答案 1 :(得分:1)

只有在获得用户ID后,才需要对小行星发起请求。因此,您的代码应位于用户数据的订阅结果中。

否则,这取决于您收到响应的顺序:如果您在之前获得小行星,则this.user尚未设置。

您可以在每个事件处理程序中看到console.log,这很明显。

因此,您的代码将变为:

getUserFeed() {
this.authService.userData$.subscribe(data => {
  this.user = data;
  this.userAsteroid$ = this.userAsteroidService.getAsteroids();

  this.userAsteroid$.subscribe(asteroids => {
    asteroids.forEach(document => {
      if (document.userId == this.user.uid) {
        console.log(document.asteroidId);
        this.dataArray.push(document.asteroidId);
      }
    });
  });});
}