DEV Community

Brian Love
Brian Love

Posted on • Originally published at lookout.dev

Lazy Load Images with Angular

I order to improve a page's Time to Interactive (TTI) and First Contentful Paint (FCP) I created an Angular directive that uses the popular lazysizes JavaScript library to lazy load images.

Install lazysizes

To get started, you need to first install the library via npm (or yarn):

npm i lazysizes
Enter fullscreen mode Exit fullscreen mode

LazyDirective

Next, create a new lazy.directive.ts file:

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

import 'lazysizes';
import 'lazysizes/plugins/unveilhooks/ls.unveilhooks';

// tslint:disable:no-input-rename
@Directive({
  selector: '[appLazy]'
})
export class LazyDirective implements AfterViewInit {
  /** The native element. */
  el: HTMLElement | null = null;

  /** The HTMLElement background-image value. */
  @Input('data-bg') dataBg: string | null = null;

  /** The HTMLImageElement sizes attribute. */
  @Input('data-sizes') dataSizes: string | null = null;

  /** HTMLImageElement src attribute. */
  @Input('data-src') src: string | null = null;

  /** HTMLImageElement srcset attribute. */
  @Input('data-srcset') srcSet: string | null = null;

  /** A transparent gif. */
  transparent = 'data:image/gif;base64,R0lGODlhAQABAAAAACH5BAEKAAEALAAAAAABAAEAAAICTAEAOw==';

  constructor(private readonly elementRef: ElementRef, private readonly renderer: Renderer2) {}

  ngAfterViewInit(): void {
    if (!this.elementRef.nativeElement) {
      return;
    }
    this.el = this.elementRef.nativeElement;

    if (this.el.tagName.toUpperCase() === 'IMG') {
      (this.el as HTMLImageElement).src = this.transparent;
      if (this.dataSizes) {
        this.renderer.setAttribute(this.el, 'data-sizes', this.dataSizes);
      }
      if (this.src) {
        this.renderer.setAttribute(this.el, 'data-src', this.src);
      }
      if (this.srcSet) {
        this.renderer.setAttribute(this.el, 'data-srcset', this.srcSet);
      }
    } else {
      this.renderer.setStyle(this.el, 'background-image', `url(${this.transparent})`);
      if (this.dataBg) {
        this.renderer.setAttribute(this.el, 'data-bg', this.dataBg);
      }
    }
    this.renderer.addClass(this.el, 'lazyload');
  }
}
Enter fullscreen mode Exit fullscreen mode

Implement lazy loading

Finally, here is the implementation in a template:

<!-- HTMLElement background -->
<div class="avatar" lktLazy [data-bg]="user.photoURL"></div>

<!-- HTMLImageElement src -->
<img lktLazy [data-src]="user.photoURL" [attr.alt]="user.displayName" />

<!-- HTMLImageElement srcset -->
<img 
  lktLazy 
  data-srcset="image1.jpg 300w,
    image2.jpg 600w,
    image3.jpg 900w" 
  [attr.alt]="user.displayName"
/>
Enter fullscreen mode Exit fullscreen mode

Learn in Public

If you're like me, you are constantly learning. Further, I love to share what I learn in public.

My biggest roadblock to learning in public is taking the time to write a long blogpost. So, I made lookout.dev to make it easy to learn in public.

Checkout my other lookouts, along with the lookout to create an Angular Directive to lazy load images with Angular.

Cheers!

Top comments (0)