How to get the data of an img loaded from a src url locally?

I have a list of images which have all src retrieved from backend API:

<div class="repoContent">     <div *ngFor="let item of repo.value" class="repoItem">         <img [src]="fetchImage(item.name)" (click)="selectAsset(fetchImage(item.name))" alt="">     </div> </div> 

After users can see the images they can click on them to put one to ngx-image-cropper for editting. Here I am using urls again as inputs. (could be blobs base64)

The thing is:
For each time I clicked on an image, another http request was fired to my backend for the image while I assume those were cached locally. As I can see those images, I think the data is somewhere stored at client machine that I can get then pass the blob data to ngx-image-cropper without using urls in order to avoid requesting backend again. How could I do that?


update for functions:

selectAsset(url){     this.imageSelected=true;     this.imageFile=null;     this.imageURL=url;   }   fetchImage(name:String):String{     return GlobalParameterService.apiAssetGet+"?name="+name;   } 

selectAsset resets cropper and put url in.
fetchImage builds target url

Add Comment
1 Answer(s)

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

Answered on July 15, 2020.
Add Comment

Your Answer

By posting your answer, you agree to the privacy policy and terms of service.