angularangular-directive

Angular img loading directive


I am trying to make a simple directive. When the image is loading, the img src will be set to an @Input() string field. On load, the image will be set to the original src value (or at least how I am trying to implement it).

I was using the answer here: https://stackoverflow.com/a/38837619/843443 but is isn't a directive, and thus would require a number of changes wherever I use images.

My first attempt:

loading-img.directive.ts:

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

@Directive({
  selector: '[tohLoadingImg]'
})
export class LoadingImgDirective {
  imgSrc: String;

  @Input()
  spinnerSrc: String;

  constructor(private el: ElementRef) {
    this.imgSrc = el.nativeElement.src;
    el.nativeElement.src = this.spinnerSrc;
  }

  @HostListener('load') onLoad() {
    this.el.nativeElement.src = this.imgSrc;
  }

}

from:

<img src="{{hero.imgUrl}}" alt="Random first slide">

to:

<img src="{{hero.imgUrl}}" alt="Random first slide" [tohLoadingImg]="'/assets/ring.svg'">

Error:

Can't bind to 'tohLoadingImg' since it isn't a known property of 'img'. (".imgUrl}}" alt="Random first slide">-->

What am I missing?


Solution

  • Try this

    import {
      Directive,
      Attribute,
      Renderer2,
      ElementRef,
      HostListener } from '@angular/core';
    
    @Directive({
      selector: '[uiImageLoader]'
    })
    export class UiImageLoaderDirective {
      constructor(
        @Attribute('loader') public loader: string,
        @Attribute('onErrorSrc') public onErrorSrc: string,
        private renderer: Renderer2,
        private el: ElementRef) {
          this.renderer.setAttribute(this.el.nativeElement, 'src', this.loader);
        }
    
      @HostListener('load') onLoad() {
        this.renderer.setAttribute(this.el.nativeElement, 'src', this.el.nativeElement.src);
      }
      @HostListener('error') onError() {
        this.renderer.setAttribute(this.el.nativeElement, 'src', this.onErrorSrc);
      }
    }
    

    USAGE

    <img
      uiImageLoader
      onErrorSrc="/assets/images/no-available-800.png"
      loader="/assets/images/image-loader.svg"
      [src]="post.imagePath" [alt]="post.title">