在 ngFor 中使用带有 angularfire2 的 firebase-src 指令失败

Posted

技术标签:

【中文标题】在 ngFor 中使用带有 angularfire2 的 firebase-src 指令失败【英文标题】:Failing using firebase-src directive inside ngFor with angularfire2 【发布时间】:2020-08-03 17:21:40 【问题描述】:

我是 Angular 新手,非常新,我正在尝试创建一个以 Firebase 作为后端的小型 Angular 应用程序。 我能够从 Firestore 检索文档列表并通过组件显示它,但我现在要做的是显示存储在 Firebase 存储中的图像,在迭代 Firestore 文档列表的 ngFor 内。 在查看 AngularFire2 的文档时,我发现 firebase-src 指令是一种可能的解决方案,但是当我尝试将其添加到我的组件模板时,图像未显示并且控制台显示警告

无法绑定到“firebase-src”,因为它不是“img”的已知属性。

我确定我做错了什么,可能我遗漏了一些东西,但正如我之前所说,我是 Angular 的新手,就像一周前开始的那样。

那么,问题是,如何将 Firebase 存储中的图像加载到这个场景中? 或许 有可能实现吗?

下面是代码sn-ps:

pets.module.ts

import  NgModule  from '@angular/core';
import  CommonModule  from "@angular/common";

import  PetsRoutingModule  from "./pets-routing.module";

import  PetsPageComponent  from './pets-page.component';
import MatGridListModule from '@angular/material/grid-list';
import  MatCardModule  from '@angular/material/card';
import  MatButtonModule  from '@angular/material/button'
import  AngularFirestoreModule  from '@angular/fire/firestore';
import  AngularFireStorageModule  from '@angular/fire/storage';
import  FlexLayoutModule  from '@angular/flex-layout'

@NgModule(
    imports: [
        CommonModule,
        PetsRoutingModule,
        MatGridListModule,
        AngularFirestoreModule,
        MatCardModule,
        MatButtonModule,
        FlexLayoutModule,
        AngularFireStorageModule
    ],
    declarations: [       
        PetsPageComponent,
    ]
)
export class PetsModule  

pets-page.component.ts

import  Component, OnInit  from '@angular/core';
import  AngularFirestore, AngularFirestoreCollection  from '@angular/fire/firestore';
import  AngularFireStorage  from '@angular/fire/storage';
import  Observable  from 'rxjs';
import  map  from 'rxjs/operators';

export interface Pet
  name:string;
  breed:string;
  imagepath:string;
  birthdate:object;
  gender:string;
  microchip:string;
  sterilized:boolean;
  userid:string;


@Component(
  selector: 'app-pets-page',
  templateUrl: './pets-page.component.html',
  styleUrls: ['./pets-page.component.scss']
)

export class PetsPageComponent implements OnInit

  collection: AngularFirestoreCollection<Pet>;
  petsList: Observable<Pet[]>;  

  constructor(private firestore: AngularFirestore, public storage: AngularFireStorage)

  

  calculateAge(birthday) 
    var ageDifMs = Date.now() - birthday.toDate();
    const oneyear = new Date('01/01/1971');
    var ageDate = new Date(ageDifMs);

    if(ageDate.getMilliseconds() < oneyear.getMilliseconds())
    
      return (ageDate.getMonth()+1) + ' meses';
    
    else
    
      var yearAge = Math.abs(ageDate.getUTCFullYear() - 1970);
      if(yearAge > 1)
      
        return yearAge + ' anos';
      

      return yearAge + ' ano';
    
  

  loadImage(pet)   
    this.storage.ref(pet.imagepath).getDownloadURL().subscribe((url) => 
      pet.imageUrl = url;
    );
  

  ngOnInit(): void 
    this.collection = this.firestore.collection('pets');
    this.petsList = this.collection.snapshotChanges().pipe(
      map(actions => actions.map(a => 
        const data = a.payload.doc.data() as Pet;        
        const id = a.payload.doc.id;
        return  id, ...data ;
      ))
    );
  

pets-page.component.html

<div class="row">
  <div fxLayout="row" fxLayout.xs="column" fxLayoutWrap fxLayoutGap="0.5%" fxLayoutAlign="center start">
    <mat-card *ngFor="let item of petsList | async" class="m-1" id="item.id">
      <mat-card-header>
        <div mat-card-avatar class="pet-avatar-img"></div>
        <mat-card-title>
          item.name
        </mat-card-title>
        <mat-card-subtitle>
          item.breed
          <br />
          calculateAge(item.birthdate)
        </mat-card-subtitle>
      </mat-card-header>      
      <img firebase-src=" item.imagepath "/>
      <mat-card-content>
        
      </mat-card-content>
      <mat-card-actions class="text-right">
        <button mat-icon-button id=item.id><i class="fa fa-edit"></i></button>
        <button mat-icon-button id=item.id><i class="fa fa-trash"></i></button>
      </mat-card-actions>
    </mat-card>
  </div>    
</div>

【问题讨论】:

【参考方案1】:

好的,找到了解决方案,但不是使用 angularfire 指令。 我创建了一个纯管道来处理将存储到 Firestore 文档中的图像路径转换为存储中的下载 url。

下面是管道的代码和使用方法:

import  Pipe, PipeTransform  from '@angular/core';
import  AngularFireStorage  from '@angular/fire/storage';

@Pipe(
    name: 'storageurl',
    pure: true
  )

  export class StorageUrlPipe implements PipeTransform   

    constructor(private storage: AngularFireStorage)

    

    transform(value: string, args?: any): any 
      return this.storage.ref(value).getDownloadURL();
    

  

实施:

&lt;img mat-card-image src="item.imagepath | storageurl | async" class="pet-image"/&gt;

注意模板中使用的异步管道。 这是必要的,因为 storageurl 管道将返回一个需要解析以从存储中检索 url 的 observable。

我不知道这是否是一个干净的最佳实践解决方案,我一周前开始使用 angular,但现在看起来不错。

【讨论】:

以上是关于在 ngFor 中使用带有 angularfire2 的 firebase-src 指令失败的主要内容,如果未能解决你的问题,请参考以下文章

引导模式 + Angularfire2

在ngFor中使用ngfire2的firebase-src指令失败。

具有嵌套 Observable/FirebaseObjectObservable 的 Angular2 ngFor 在更新时闪烁一些数据

带有 ngFor 输入的 Angular 2 模板驱动表单

angular/cdk 简单拖动不适用于带有 ngFor 的 div

Angular2:输入控制带有ngFor的表单标签内的损失值