首页 > 解决方案 > 将 Firestore 可观察对象投射到自定义对象

问题描述

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

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

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

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

当前代码

自定义模型类

export class Blimp {


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

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

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

}

服务等级

    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;

标签: javascriptangularfirebasegoogle-cloud-firestoreangularfire2

解决方案


概念 :

您不会将 observable 转换为对象模型。可观察对象是具有生命周期的流。
一个observable向它的订阅者发出值,你需要订阅你的 observable 以便在它发出值时得到通知。您还需要关闭订阅,否则订阅将持续到您的 observable完成导致内存泄漏
我可以看到您| asynchtml 模板中使用,它是由 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"

编辑 :

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

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

推荐阅读