How to Prevent image from loading that comes from server side

Viewed 652

I have API data with images, but due to internet problems or something else images are taking too much time to completely loaded.

Is there any way to prevent this loading because it looks bad when all data is loaded and images still taking time to display.

menu.html

<ion-card class="categories_item" *ngFor="let category of categories; let i = index;">
  <ion-grid>
    <ion-row>
      <ion-col size-md="2" size="4" class="img-zoom" align-self-center>
        <img [src]="category?.Picture1" (click)="imgView(category?.Picture1)" id="imgClickAble"
          class="imgClickAble" />
          .....
      </ion-col>

      <ion-col size-md="9" size="6" (click)="goToitemCategory(category.ID)">
        .....
      </ion-col>
    </ion-row>
  </ion-grid>
</ion-card>

I need to show something else until the complete image loaded like a place holder or I want to cache images for future use.

2 Answers

You can hide original image and use a place holder image in your loop and call original image onload function to hide place holder image and show actual image

<img src="placeholderurl" id="placeholder_{{i}}" >

<img [src]="category?.Picture1" class="hidden" id="original_{{i}}" (load)="onImageLoad(i)">

you onimageload function will look like

onImageLoad(idx){
  var orginalEle=document.getElementById(`original_${idx}`)
  var placeHolderEle=document.getElementById(`placeholder_${idx}`);
  placeHolderEle.classList.add('hidden');
  orginalEle.classList.remove('hidden');
}

Demo

I created a stackblitz project: https://stackblitz.com/edit/angular-dynamic-image-directive

First, create a custom directive. In the constructor, inject the ElementRef of the img tag and set the default value to src attribute.

And in OnInit callback, create a new Image() and set the new source. In the onload callback, set the new source to the ElementRef to the img tag

Hope this helps.

This is the directive:

import { Directive,  ElementRef, Input,Renderer2, OnInit} from '@angular/core';

@Directive({
  selector: '[appDynamicImage]'
})
export class DynamicImageDirective implements OnInit {

  @Input()
  dynamicSrc: string;

  private defaultSrc = 'https://via.placeholder.com/500x300';

  constructor(private elem: ElementRef,
  private renderer: Renderer2) { 
    this.setSource(this.defaultSrc);
  }

  ngOnInit(){
    setTimeout(() => { // just to mock loading time
      this.setAsyncSource(this.dynamicSrc);
    },2000)

  }

  setAsyncSource = (src: string) => {
    const dynamicImage = new Image();
    dynamicImage.onload = (e) => {
      console.log('onload', e)
      this.setSource(src);
    }

    dynamicImage.onerror = (e) => {
      console.log('Error happened', e)
    }

    dynamicImage.src = src;
  }

  setSource = (src: string) => {
    this.renderer.setAttribute(this.elem.nativeElement,'src',src);
  }

}

This is the template:

<img appDynamicImage [dynamicSrc]="'https://www.fillmurray.com/640/360'"/>
Related