【问题标题】:AngularFire / Firestore - Return collections and documents as a serviceAngularFire / Firestore - 作为服务返回集合和文档
【发布时间】:2018-07-01 00:44:21
【问题描述】:

我有几个页面引用了 firestore 中的同一个节点,每个页面都从 firestore 节点中提取不同的段。例如,摘要页面可能会显示专辑标题、日期、流派和图像,而另一个页面可能只会显示标题、艺术家和唱片公司。几个问题:

  1. 是否可以将其中一个 firestore 查询转换为服务?
  2. 如果是这样,这是否意味着在使用相同服务的不同页面(角度组件)之间导航时只读取一次数据?
  3. 只有在通过 observable 在 Firestore 中修改数据时,查询才会再次运行? ("return Observable.create(observer => {")

我已尝试使用以下代码提供服务。但是,观察到的问题是在页面刷新时,数据不存在。但是,它在浏览该站点时存在。我相信这是因为我的页面在 observable 返回之前正在运行。有没有办法将查询包装为可观察对象?

任何帮助将不胜感激。

getAlbumData() {
  this.albumDoc = this.afs.doc(`albums/${this.albumId}`);
  this.album = this.albumDoc.snapshotChanges();
  this.album.subscribe((value) => {

    // The returned Data
    const data = value.payload.data();

    // Firebase Reference
    var storage = firebase.storage();

    // If album cover exists
    if (data.project_signature != undefined) {

      // Get the Image URL
      var image = data.album_cover_image;

      // Create an image reference to the storage location
      var imagePathReference = storage.ref().child(image);

      // Get the download URL and set the local variable to the result (url)
      imagePathReference.getDownloadURL().then((url) => {
        this.album_cover = url;
      });
    }
  });
}

【问题讨论】:

    标签: javascript angular google-cloud-firestore angular-services angular2-observables


    【解决方案1】:

    当我构建我的 observables 时,我会尽可能多地使用运算符,直到我获得想要在我的 UI 中显示的数据。

    您不想在 subscribe 方法中实现太多代码,因为这样做会破坏反应式范式。 相反,在您的 observable 中提取数据并将其显示在您的模板中。 不要忘记在您的应用程序获取数据时使用模板中的异步管道来显示您的数据。

    我会这样做:

    // In AlbumService
    getAlbumCover(albumId: string) {
        const albumDoc = this.afs.doc(`albums/${albumId}`);
        const album_cover$ = this.albumDoc.snapshotChanges().pipe(
          // get the album data from firestore request
          map(data => {
            return {
              id: data.payload.id,
              ...data.payload.data()
            };
          }),
          // emits data only if it contains a defined project_signature
          filter(album => album.project_signature),
          // prepare the imagePath and get the album cover from the promise
          mergeMap(album => {
            const storage = firebase.storage();
            const image = album.album_cover_image;
            const imagePathReference = storage.ref().child(image);
            return imagePathReference.getDownloadURL();
          })
        );
        return album_cover$;
      }
    

    通过这样做,当您的数据在 firestore 中更新时,您的应用程序会自动获取数据,因为您使用的是 observable。

    在您的组件中,在从 url 获取专辑 ID 后的 onInit() 方法中: this.album_cover$ = this.albumService.getAlbumCover(albumId);

    最后,在我的模板中,我会这样做:

    <div>{{album_cover$ | async}}</div>

    【讨论】:

    • 谢谢昆汀。 map、filter 和 mergeMap 是否有特定的导入?打字稿似乎对此抛出了错误。使用上面的代码,我可以将它作为服务简单地导入到其他组件和模块中吗?
    • 是的,每个算子都需要单独导入。例如,在您的情况下,如果您想导入地图、mergeMap 和过滤器,则需要添加:import { map, mergeMap, filter } from 'rxjs/operators'; 是的,您可以将其放入服务中以从任何组件访问您的数据。
    • 对迟到的回复表示歉意。我不断收到“属性 'snapshotChanges' 在类型 'Observable' 上不存在”。在“this.album_cover = line”上。要提取标题、日期等其他数据,是否会在“...data.payload.Data()”下的第一个返回中引用?比如'this.albumTitle = data.albumTitle'?此外,这种方法如何也适用于集合?
    • 哎呀,我的小错误,因为我连续两次调用了 snapshotChanges 方法。 data 方法也以小写字母开头。我已经在我的答案中改变了它。现在应该是正确的。文档的所有属性都由 data 方法返回。所以,如果你想访问你的属性“albumTitle”,你可以写:data.payload.data().albumTitle。对于集合,它几乎相同,但它返回一个数组。查看此链接了解更多详情:github.com/angular/angularfire2/blob/master/docs/firestore/…
    • 啊太棒了。谢谢你。我试试看! - 另外,如果它在服务中,是否最好将上述所有代码放入构造函数中? (比如 AngularFire 文档中的内容?)
    猜你喜欢
    • 2019-11-13
    • 2020-02-27
    • 1970-01-01
    • 1970-01-01
    • 2018-10-09
    • 2018-08-11
    • 1970-01-01
    • 2018-06-19
    • 1970-01-01
    相关资源
    最近更新 更多