Image With Lazy Loading Placeholder In Angular

Reading Time: 3 minutes
Angular development, Hire Angular Developer, Angular Web Development  Company India

Introduction

We all are familiar with the word lazy loading in Angular Ecosystem. However, when it comes to loading images from a third party either from AWS S3 or others, the time taken (Response Time) by the foreign URL plays a vital role.

A big factor that affects front-end performance is the amount of documents and assets being loaded on a web page. We’ve used variety of techniques to reduce the amount of assets being loaded when a user lands on the page like minifying the files we serve, compressing & caching images and recently we’ve added lazy loaded images to our home page.

Lazy loading is a pattern for loading content (in this context images) when it’s needed, rather than loading it all at once. This helps us decrease the amount unnecessary bytes being loaded for content that is not currently seen by the user (a.k.a. below the fold content)

Main Challenge

The pitfall that I’ve discovered is the fact that a few of the available lazy loading tools require me to specify a height or width in order to have a blank space for placing the image while it’s loading. Specifying a height is tricky because our images are responsive and their aspect ratios and dimensions depend on the size of the user’s screen or browser.

Other Implementations

This blog post by David Calignano handles some image loading scenarios.

Implementation

ng g c <image-loader-component>

image.loader.component.ts

import { Component, Input } from "@angular/core";
@Component({
selector: "app-image-loader",
templateUrl: "./image-loader.component.html",
styleUrls: ["./image-loader.component.scss"],
})
export class ImageLoaderComponent{
 @Input() imageLoading: boolean = false;
 @Input() imageLoaded: boolean = false;
 @Input() imageUrl: string = "";
 @Input() imageLoadingUrl: string = "";
 @Input() noImageUrl: string = "";
 @Input() alt: string = "";
 @Input() imageId: string = "";
 @Input() imageHeight: string = "";
 @Input() imageWidth: string = "";
 @Input() imageClass: string = "";
onImageLoaded() {
  this.imageLoading = false;
}
handleEmptyImage() {
  this.imageLoading = false;
  this.imageUrl = this.noImageUrl;
 }
}

I have created a list of input properties. All are self-explanatory.

image.loader.component.html

<ng-container>
   <img
     [src]=”imageLoading ? imageLoadingUrl : imageUrl”
     [alt]=”alt”
     [id]=”imageId”
     (load)=”onImageLoaded()”
     (error)=”handleEmptyImage()”
     loading=”lazy”
     [ngClass]=”imageClass”
     [height]=”imageHeight”
     [width]=”imageWidth”
   />
 </ng-container>

(load) – when image is loaded successfully load event is triggered.
(error) – The error event is triggered if an error occurs while loading an external file (e.g. a document or an image).

Here are the supported values for the loading attribute:

  • auto: Default lazy-loading behaviour of the browser, which is the same as not including the attribute.
  • lazy: Defer loading of the resource until it reaches a calculated distance from the viewport.
  • eager: Load the resource immediately, regardless of where it’s located on the page.

So now we have created our generic component, let’s do some changes to the parent component.

app.component.html

<ng-container *ngIf="currentData && currentData.length">
    <div *ngFor="let data of currentData; let i = index">
      <app-generic-image-loading-component 
        [alt]="data.title"          
        [id]="'id-'+data.id" 
        [imageLoading]="data.imageLoading"  
        [imageLoadingUrl]="'loading-spinner-gif or svg '"
        [imageUrl]="data.thumbnailUrl"       
        [noImageUrl]="'no-image-url'" 
        [imageHeight]="'100'"  
        [imageWidth]="'80'">
      </app-generic-image-loading-component>
    </div>
</ng-container>
  • [imageLoading] – Boolean value representing weather image is loaded or not .
  • [imageLoadingUrl] – String value url which will be used until image is loaded .
  • [imageUrl] – String value url which will be used when image finished loading .
  • [noImageUrl] – Image to be shown when loaded image has broken url .

app.component.ts

export class AppComponent implements OnInit {
    getData() {
      // http call for getting list of data 
      // make sure you create loading property or either get it from backend 
      // and set it initially false
    }

    ngOnInit(): void {
      this.getData();
    }
}

And you are done…

Conclusion

Progressive image loaders allow users to see a lower quality image while your website loads the larger image in the background, and handles image errors without showing ugly broken image links.

Using generic components for image loading scenarios allows you to create reusable components which provide both common logic and markup out of the box.Using such generic components we can ignore the possibility of duplication.

Demo : Image Loader

Leave a Reply