62

If an image on a separate server doesn't exist I'd like to display a default image. Is there an angular directive to accomplish this?

Matt York
  • 15,981
  • 7
  • 47
  • 51
  • Not that I've seen, but it wouldn't be hard to write one. – Josh David Miller May 02 '13 at 23:59
  • Possible duplicate of [if a ngSrc path resolves to a 404, is there a way to fallback to a default?](https://stackoverflow.com/questions/16310298/if-a-ngsrc-path-resolves-to-a-404-is-there-a-way-to-fallback-to-a-default) – Jon Onstott Jul 05 '17 at 18:41

5 Answers5

128

No but you can create one.

http://jsfiddle.net/FdKKf/

HTML:

<img fallback-src="http://google.com/favicon.ico" ng-src="{{image}}"/>

JS:

myApp.directive('fallbackSrc', function () {
  var fallbackSrc = {
    link: function postLink(scope, iElement, iAttrs) {
      iElement.bind('error', function() {
        angular.element(this).attr("src", iAttrs.fallbackSrc);
      });
    }
   }
   return fallbackSrc;
});
Rubens Mariuzzo
  • 28,358
  • 27
  • 121
  • 148
Ketan
  • 5,861
  • 3
  • 32
  • 39
  • 1
    Nice! I only want to add, that if he hasn't jQuery included, he should write iElement.on('error',function() { – kfis May 03 '13 at 08:39
  • Not sure why I put `angular.element` but `iElement` may have worked too – Ketan Aug 18 '13 at 15:14
  • how do you enforce the same size on this image that applies to the images you are "falling back" on? – natecraft1 Oct 11 '13 at 03:02
  • thru css or width and height attributes. Assuming that they all will be of the same size. – Ketan Oct 11 '13 at 03:37
  • 4
    This is a good directive. I had a problem with it because the ng-src could also be a null value. Here was my fix. I hope it helps. https://gist.github.com/jpotts18/7161375 – jpotts18 Oct 25 '13 at 20:32
  • Note that the standard onerror attribute works fine as well unless there's interpolation within the fallback value. – Lukus Apr 16 '14 at 19:22
  • 3
    just use `iAttrs.$set('src', iAttrs.fallbackSrc)` – atian25 May 19 '14 at 07:45
  • Instead, I would use $(element).one(...) (or unbind the event after it is consumed) to ensure you don't get a recursive error handling loop if the replacement image doesn't exist. – nokturnal Feb 05 '15 at 15:12
  • This works, but not smooth enough. In case the image not found, you may see for the some short time a default browser icon for "missing resource", and right after that it being replaced by image from 'fallback-src'. So user sees kind of flick, and personally I think this is not good experience. – Illidan Mar 12 '15 at 07:22
  • I've tried similar one for `audio` it seems doesn't work for `audio` 404's . any idea ? – Davut Gürbüz Sep 22 '15 at 14:36
  • How do you invoke some function instead? for example, if image is not loaded, raise modal with error notice – Dalibor Apr 03 '17 at 08:49
  • 1
    @Dalibor instead of this line `angular.element(this).attr("src", iAttrs.fallbackSrc);` You need to add the code to invoke the modal. – Ketan Apr 06 '17 at 14:32
3

Is there an angular directive...

http://ngmodules.org/modules/angular-img-fallback

Github: https://github.com/dcohenb/angular-img-fallback

(32 stars as of now)

Mars Robertson
  • 12,673
  • 11
  • 68
  • 89
2

Angualr 2 Version

https://github.com/VadimDez/ng2-img-fallback

HTML

<img fallback-src="http://google.com/favicon.ico" src="http://google.com/failedImage.png"/>

Angular 2 Component

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

@Directive({
  selector: '[fallback-src]'
})
export class FallbackSrc {

  @Input('fallback-src') imgSrc: string;
  private el: HTMLElement;
  private isApplied: boolean = false;
  private EVENT_TYPE: string = 'error';

  constructor(el: ElementRef) {
    this.el = el.nativeElement;
    this.el.addEventListener(this.EVENT_TYPE, this.onError.bind(this))
  }

  private onError() {
    this.removeEvents();

    if (!this.isApplied) {
      this.isApplied = true;
      this.el.setAttribute('src', this.imgSrc);
    }
  }

  private removeEvents() {
    this.el.removeEventListener(this.EVENT_TYPE, this.onError);
  }

  ngOnDestroy() {
    this.removeEvents();
  }
}
Michael Warner
  • 3,879
  • 3
  • 21
  • 45
1

I wrote my own fallback lib.

A pretty simple and straightforward angular fallback image lib:

https://github.com/alvarojoao/angular-image-fallback

Utility to work with loading images and handling image error, has image-holder to handle errors in image loading and image-loading for images loading placeholders

http://alvarojoao.github.io/angular-image-fallback

Usage

Just add the image attribute to your <img /> tags

<img image="{{'path/to/img.jpg'}}" />

Make sure you don't use ng-src as your image src attribute.

Advanced options

with custom fallback and loading placeholders:

<img image="{{image.url}}" image-loading="/image/loading.gif" 
     image-holder="/image/error.png" />

Example:

https://jsfiddle.net/alvarojoao/4wec4gsq/embedded/result/

Alvaro Silvino
  • 9,441
  • 12
  • 52
  • 80
1

I think this will also work

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

@Directive({
  selector: 'img[imgFallback]',
})

export class DefaultImageDirective{ 
  public defaultImg: string = './assets/img/default-image-placeholder.svg';
  @Input() src!: string;

  @HostBinding('src') 
  get originalSrc() {
    return this.src;
  }

  @HostListener('error') onError() {
    this.src = this.defaultImg;
  }
}

Usage:

<img imgFallback [src]="productItemImage" alt="Sample alt text" />
Gabo3D
  • 51
  • 2