将 firestore observable 转换为自定义对象

4 javascript firebase angularfire2 angular google-cloud-firestore

我是 Angular 和 Firestore 的新手,并试图弄清楚如何将从 Firebase 接收到的数据直接转换为模型。这里最好的方法是什么?

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

错误 TypeError: _v.context.$implicit.getImageUrl 不是函数

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

当前代码

自定义模型类

export class Blimp {


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

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

getImageUrl() {
    return "https://*.com" + this.file_location;
}
Run Code Online (Sandbox Code Playgroud)

}

服务等级

    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;
  }
}
Run Code Online (Sandbox Code Playgroud)

显示组件

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();
  }

}
Run Code Online (Sandbox Code Playgroud)

看法

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

更新#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;
  }
Run Code Online (Sandbox Code Playgroud)

这仍然在视图中抱怨在对象上找不到 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;
Run Code Online (Sandbox Code Playgroud)

Flo*_*ian 5

概念 :

您不会将可观察对象转换为对象模型。可观察对象是具有生命周期的流。
Observable向其订阅者发出值,您需要订阅您的 Observable,以便在它发出值时收到通知您还需要关闭订阅,否则订阅将持续到您的可观察完成为止,从而导致内存泄漏。我可以看到您在html 模板中 使用,它是由 Angular 处理的订阅,在需要时自动取消订阅。
| async

获取数据:

您需要将收到的数据映射到对象Blimp,可以使用map 运算符

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;
Run Code Online (Sandbox Code Playgroud)

正如我们更改blimps为的那样blimps$,更改您的 html 模板:

*ngFor="let blimp of blimps$ | async"
Run Code Online (Sandbox Code Playgroud)

编辑 :

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

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));
                }));
Run Code Online (Sandbox Code Playgroud)