将 firestore observables 投射到自定义对象

Casting firestore observables to custom objects

我是 angular 和 firestore 的新手,正在尝试弄清楚如何将从 firebase 接收的数据直接转换为模型。这里最好的方法是什么?

目前我得到了数据,但看起来它没有被转换成 Blimp 对象。当我尝试在视图中对其调用 getImageUrl() 时,我收到以下错误消息。

ERROR TypeError: _v.context.$implicit.getImageUrl is not a function

所以我的问题是:将这些可观测值转换为正确的本地模型的最佳和最干净的方法是什么?我原以为标签会默认投射它。

当前代码

自定义模型 class

export class Blimp {


created_at: Date;
file_location: string;
id: string;

constructor() {
    console.log('OBJ');
}

getImageUrl() {
    return "https://*.com" + this.file_location;
}

}

服务class

    import { Injectable } from '@angular/core';
import {Blimp} from '../models/blimp';
import { AngularFirestore } from '@angular/fire/firestore';
import {AngularFireStorage, AngularFireUploadTask} from '@angular/fire/storage';
import {Observable} from 'rxjs';
import {finalize} from 'rxjs/operators';

@Injectable({
  providedIn: 'root'
})
export class BlimpService {

   blimps: Observable<Blimp[]>;

  constructor(private fireStore: AngularFirestore, private fireDisk: AngularFireStorage) { }


  getBlimps() {
      this.blimps = this.fireStore.collection<Blimp>('blimps').valueChanges();

      return this.blimps;
  }
}

显示组件

import { Component, OnInit } from '@angular/core';
import {BlimpService} from '../../services/blimp.service';
import {Observable} from 'rxjs';
import {Blimp} from '../../models/blimp';

@Component({
  selector: 'app-blimp-viewer',
  templateUrl: './blimp-viewer.component.html',
  styleUrls: ['./blimp-viewer.component.scss'],
})
export class BlimpViewerComponent implements OnInit {

  blimps: Observable<Blimp[]>;

  constructor(private blimpService: BlimpService) { }

  ngOnInit() {
    this.blimps = this.blimpService.getBlimps();
  }

}

查看

<ul>
  <li *ngFor="let blimp of blimps | async">
      {{ blimp | json}}
      <img [src]="blimp.getImageUrl()" />
  </li>
</ul>

更新 #1

将代码更改为

我现在已将您的示例更改为:getBlimps() {

   this.blimps = this.fireStore.collection<Blimp>('blimps')
          .valueChanges()
            pipe(map(b => {
                let blimp = new Blimp();
                blimp.created_at = b.created_at;
                blimp.file_location = b.file_location;
                blimp.id = b.id;

                return blimp;

            }));

      return this.blimps;
  }

这仍然在视图中抱怨未在对象上找到 getImageUrl()。

#解法

看来我忘记了一个 . (点)在最后一个代码

此代码有效:

this.blimps = this.fireStore.collection<Blimp>('blimps')
      .valueChanges()
      .pipe(map(collection => {
            return collection.map(b => {
                let blimp = new Blimp();
                blimp.created_at = b.created_at;
                blimp.file_location = b.file_location;
                blimp.id = b.id;

                return blimp;
            });
        }));

  return this.blimps;

概念:

您没有将可观察对象转换为对象模型。可观察对象是具有生命周期的流。
一个 observable 它的订阅者 发出值,你需要订阅你的 observable 以便在它发出值时得到通知。您还需要关闭订阅,否则订阅将持续到您的可观察 完成 导致 内存泄漏 .
我可以看到您在 html 模板 中使用了 | async,它是由 angular 处理的订阅,在需要时自动取消订阅。

获取数据:

您需要将收到的数据映射到一个Blimp对象,可以使用map operator.

blimps$: Observable<Blimp[]>; // naming convention, suffix your observable with $



blimps$ = this.fireStore.collection<Blimp>('blimps')
          .valueChanges()
          .pipe(map(collection => {
                return collection.map(b => {
                    let blimp = new Blimp();
                    blimp.created_at = b.created_at;
                    blimp.file_location = b.file_location;
                    blimp.id = b.id;
                    console.log(blimp);
                    console.log(b);
                    return blimp;
                });
            }));

      return this.blimps;

当我们将 blimps 更改为 blimps$ 时,请更改您的 html 模板:

*ngFor="let blimp of blimps$ | async"

编辑:

您可以使用 class 构造函数来初始化您的对象:

export class Blimp {

created_at?: Date;
file_location?: string;
id?: string;

constructor(blimp: Blimp = {}) {
  this.created_at = blimp.created_at;
  this.file_location = blimp.file_location;
  this.id = blimp.id;
}

getImageUrl() {
    return `https://*.com${this.file_location}`; // use string interpolation here
}



blimps$ = this.fireStore.collection<Blimp>('blimps')
              .valueChanges()
              .pipe(map(collection => {
                    return collection.map(b =>  new Blimp(b));
                }));