You're triggering the request twice explicitly with the function fetchImage(item.name)
. And it's generally a bad design to bind a function to a property. If you aren't handling the change detection, the functions will be triggered multiple times.
What you could instead do is to fetch the images in the controller and use them in the template. Try the following
Controller
import { from, forkJoin } from 'rxjs';
import { map, switchMap } from 'rxjs/operators';
export class AppComponent {
imageBase64 = '';
croppedImage: any = '';
repo = {
value: [
{ name: '100' },
{ name: '200' },
{ name: '400' },
{ name: '500' }
]
};
constructor() { }
ngOnInit() {
const urls = this.repo.value.map(item => this.fetchImage(item.name));
forkJoin(urls).pipe(
switchMap(responses => {
return forkJoin(responses.map(response => this.getBase64(response)));
})
).subscribe(
(bases: Array<string>) => {
bases.forEach((base, i) => this.repo.value[i]['base'] = base);
},
err => {
console.log(err);
}
);
}
fetchImage(name) {
return from(fetch(`https://picsum.photos/id/${name}/200/200`));
}
// Credit: https://stackoverflow.com/a/20285053/6513921
getBase64(response) {
return from(response.blob().then(blob =>
new Promise((resolve, reject) => {
const reader = new FileReader();
reader.onloadend = () => resolve(reader.result);
reader.onerror = reject;
reader.readAsDataURL(blob);
})));
}
selectAsset(base: string) {
this.imageBase64 = base;
}
imageCropped(image: any) {
this.croppedImage = image.base64;
}
imageLoaded() {
// show cropper
}
loadImageFailed() {
// show message
}
}
Template
<div class="repoContent">
<div *ngFor="let item of repo.value" class="repoItem">
<img style="cursor: pointer" [src]="item.base" #img (click)="selectAsset(item.base)" alt="">
</div>
</div>
<hr>
<image-cropper
[imageBase64]="imageBase64"
[resizeToWidth]="0"
format='png'
(imageCropped)="imageCropped($event)"
(imageLoaded)="imageLoaded()"
(loadImageFailed)="loadImageFailed()"
></image-cropper>
<img [src]="croppedImage" />
Here I've used the repo
variable and https://picsum.photos
API as examples. Replace it with your own variables. I've also used RxJS from
function to convert Promises to Observables and forkJoin
function to combine multiple observables.
Working example: Stackblitz