如何将图像源绑定到 ngFor 循环内的可观察对象?
Posted
技术标签:
【中文标题】如何将图像源绑定到 ngFor 循环内的可观察对象?【英文标题】:How to bind image source to an observable inside an ngFor loop? 【发布时间】:2019-12-28 13:19:33 【问题描述】:我正在尝试在这样的 ngFor 循环中显示图像:
HTML
<div *ngFor="let leg of flight.route">
<img [src]="getImage(leg.airline) | async" />
</div>
TS
getImage(airlineCode: string): Observable<any>
return this.companyLogoService.getLogo(airlineCode);
这不起作用。当它被执行时,对getImage()
的所有请求似乎都相互中断并无限循环:
根据similar threads,处理此问题的一种方法是手动创建一个保存可观察对象的模板变量,然后将此变量传递给[src]
标记,但由于 ngFor,我不能这样做循环。
如何正确绑定这个图片源?
编辑:
对getImage()
的请求没有互相干扰。此行为是由 Angular 更改检测引起的,因为我直接将函数调用映射到 [src]
,因此我发疯了,这是不支持的。同样的问题也发生在要加载的单个图像上。
【问题讨论】:
【参考方案1】:我想说这不是一个好方法,因为更改检测经常运行,并且每次更改检测都会调用“getImage”。
您可以尝试在初始化时获取所有图像并将其填充到您的模板中
getFlights()
this.flights = /*code to get flights*/;
// after you have retrieved flights
this.flights.forEach((flight, index) =>
readImageFile(index, flight.airline);
);
getImage(index: number, airlineCode: string)
this.companyLogoService.getLogo(airlineCode)
.subscribe((result) =>
// result depends on your server i.e. base64 data, image url etc
this.flights[index].img = result;
);
<div *ngFor="let flight of flights | async;">
<img [src]="flight.img">
</div>
【讨论】:
这就是我最终做的事情,但我将图像与组件输入数据分开 您可以为图像创建一个单独的数组,但我强烈建议只运行一次此类代码,因为在这种情况下,更改检测会严重影响应用程序性能 我认为这很好,因为我现在指的是一个变量(一个可观察的数组)而不是一个函数。该数组在组件启动时填充,然后永远不会改变。【参考方案2】:使用components
执行此操作。
这里正在工作Sample
【讨论】:
我不明白你的回答与我的问题有什么关系 我已经编写了示例组件来解决您的问题,您不想将其插入到数组中 你能提供示例 api 我会映射它【参考方案3】:由于显然没有这种方法可以实现这种绑定,因此我使用了一个数组来保存我的 observables,并通过模板中的索引映射它们。
TS
@Component(
selector: 'flight-card',
templateUrl: './flight-card.component.html',
styleUrls: ['./flight-card.component.scss']
)
export class FlightCardComponent implements OnInit
@Input()
public flight: Flight;
public airlineImages: Observable<any>[];
constructor(private companyLogoService: CompanyLogoService)
ngOnInit()
this.airlineImages = [];
this.flight.route.forEach(leg =>
this.airlineImages.push(this.companyLogoService.getLogo(leg.airline));
);
HTML
<div *ngFor="let leg of flight.route; let i = index">
<img [src]="this.airlineImages[i] | async" />
</div>
【讨论】:
【参考方案4】:如上所述,变更检测会导致这种行为,它每次都会调用该方法并触发该方法(一个http请求)。
一种可行的方法是在组件初始化时加载图像。 (重要的是,在你的组件中添加一个 *ngIf,否则你的对象可能不会被初始化)
#1 父组件
<ns-bills-cardview *ngIf="billsBook" [billsBook]="billsBook"></ns-bills-cardview>
#2 在您的组件中,只需从缓存或 http 请求中加载图像
export class BillsCardviewComponent implements OnInit
@Input() billsBook: BillsBook[];
productDocuments: BillBookPrictureData[] = [];
ngOnInit(): void
this.authService.userTake1Observable.pipe(take(1)).subscribe(user =>
if (user)
// pre-loading billBook detail images
this.loadingImages();
);
onLoadImage(productUUID): string
const picture: BillBookPrictureData = this.productDocuments.find(
productDocument => productDocument.key === productUUID
);
return picture.data;
onItemTap(bill: BillsBook, productUUID: string)
this.billDetailDialogModalService.openBillDetailDialogModal(this.vcRef, this.modal, bill.uuid, productUUID);
/**
* This method will get called to re-load all billBook images
*/
private loadingImages()
this.billsBook.forEach(bill =>
const billUUID = bill.uuid;
bill.products.forEach(product =>
const billBookPicture: BillBookPrictureData = key: null, data: null ;
// cache billPictureData
billBookPicture.key = product.productDocument.uuid;
billBookPicture.data = this.loadImage(billUUID, billBookPicture.key);
this.productDocuments.push(billBookPicture);
);
);
/**
* This method will load all images from appSettings or send http request
* @param string billUUID
* @param string productUUID
*/
private loadImage(billUUID: string, productUUID: string): string
//load billBook images from cache
if (this.appSettingsService.hasBillDetailFileData(billUUID, productUUID))
return this.appSettingsService.getBillDetailFileData(billUUID, productUUID);
//load billBook images via http request
this.documentControllerService
.getDocumentFileDataUsingGET(productUUID)
.pipe(take(1))
.subscribe(
fileData =>
//store image in cache
this.appSettingsService.setBillDetailFileData(fileData, billUUID, productUUID);
//push loaded image to productDocument array
const billBookPicture: BillBookPrictureData = key: productUUID, data: fileData ;
this.productDocuments.push(billBookPicture);
,
error => console.log(error)
);
#3 面具
<StackLayout *ngFor="let product of item.products" (tap)="onItemTap(item, product.uuid)">
<Image
*ngIf="productDocuments"
[src]="'data:image/jpeg;base64, ' + onLoadImage(product.productDocument.uuid)"
[alt]="product.name"
stretch="aspectFill"
></Image>
.
.
.
</StackLayout>
此解决方案可适用于加载一张或多张图片。
【讨论】:
以上是关于如何将图像源绑定到 ngFor 循环内的可观察对象?的主要内容,如果未能解决你的问题,请参考以下文章
如何将 TabControl 的项目绑定到 wpf 中的可观察集合?