Let’s say I have a list of cars:
const cars: Array<{carId: number}> = [{carId: 1}, {carId: 2}];
And I render them in a template:
<div *ngFor=“let car of cars”></div>
Inside of that template, I want to get some dynamic image paths from a method that returns an observable:
<div *ngFor=“let car of cars”>
<img [src]=“getImagePath(car) | async”>
</div>
getImagePath(car: {carId: number}): Observable<string> {
return //some service request that brings back a url based on the carId
}
For state management and storage, I’m using Firebase. All of my images are stored in a bucket and I can get to them by providing my service with a carId that uses it to fetch the downloadURL.
I want to avoid updating Firestore with downloadURL’s when the file is first saved because I’d be storing them in sub-collections and pulling them out of there is already a pain due to the nature of Firestore.
Is there a way to do this more efficiently? The code above would most certainly bring the browser to a crawl if the list starts to grow … right?
Instead of calling a request directly on every img element, you can just make it into an observable and subscribe to it once then display the returned array to your html.
I used a couple of RXJS operators to get what you want.
mergeMap
to flatten the inner observableof
to convert the cars array into an observablemap
to transform the cars array into a a new array with their corresponding car image pathforkJoin
- we wrapped multiple requests into one observable and will only return when a response has been received for all requests.This is certainly only one way to do it and there might be other better ways.
HTML:
I created a stackblitz to mock the solution.