我是一个新的angular,真的很新,我试图创建一个以firebase为后台的小型angular app.我已经能够从Firestore中检索一个文档列表,并通过一个组件来显示它,但我现在要做的是在迭代Firestore文档列表的ngFor里面显示一个存储到Firebase存储中的图片。 在查找AngularFire2的文档时,我发现firebase-src指令是一个可能的解决方案,但是当我试图将它添加到我的组件模板中时,图像没有显示出来,控制台显示了一个警告。
不能绑定到'firebase-src',因为它不是'img'的已知属性。
我肯定我做错了什么,可能我漏掉了什么,但正如我之前所说,我是一个完全陌生的Angular,就像一个星期前开始的。
所以,问题是,我怎么能把Firebase存储的图片加载到这个场景中呢,或者说,也许有可能实现?
下面是代码片段。
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>
好吧,找到了一个解决方案,但不是用angularfire指令,我已经创建了一个纯管道来处理存储在Firestore文档中的图片路径转换为存储的下载网址。
下面是这个管道的代码以及如何使用它。
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();
}
}
实现方法:
<img mat-card-image src="{{item.imagepath | storageurl | async}}" class="pet-image"/>
注意模板中使用的async管道,这是必要的,因为sorageurl管道会返回一个observable,需要通过解析才能从存储中获取url。
我不知道这是否是一个干净和最佳实践的解决方案,我一周前开始使用angular,但目前看起来不错。