Angular2: Show placeholder image if img src is not valid

JavascriptAngular

Javascript Problem Overview


Goal: Load an image with a dynamic source. If no image is found, then load a placeholder image instead.

This should demonstrate what I'm trying to do, but I don't know how to conditionally set validImage based on whether the first img src is valid.

<img *ngif="validImage" class="thumbnail-image" src="./app/assets/images/{{image.ID}}.jpg" alt="...">
<img *ngif="!validImage" class="thumbnail-image" src="./app/assets/images/placeholder.jpg" alt="...">

validImage should be true if src="./app/assets/images/{{image.ID}}.jpg" returns an image. Otherwise it would return false and only the second img tag should show.

There are obvious work arounds like storing a list of all valid image sources, but I'm thinking there is a better way to accomplish this.

Any suggestions on the best way to implement this in Angular2 would be greatly appreciated.

Javascript Solutions


Solution 1 - Javascript

The best way to handle broken image links is the use the onError event for the <img> tag:

<img  class="thumbnail-image" src="./app/assets/images/{{image.ID}}.jpg"
      onerror="this.src='./app/assets/images/placeholder.jpg';"  alt="..." />

Solution 2 - Javascript

<img [src]="pic" (error)="setDefaultPic()">

And somewhere in your component class:

setDefaultPic() {
  this.pic = "assets/images/my-image.png";
}

Solution 3 - Javascript

I ran into a similar need. I wanted to default to a 1X1 transparent pixel if an img url was null or returned an error (404 etc).

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

@Directive({
    selector: 'img[src]',
    host: {
        '[src]': 'checkPath(src)',
        '(error)': 'onError()'
    }
})
export class DefaultImage { 
    @Input() src: string;
    public defaultImg: string = '{YOUR_DEFAULT_IMG}';
    public onError() {
        this.src = this.defaultImg;
    }
    public checkPath(src) {
        return src ? src : this.defaultImg;
    }
}

Markup

<img [src]="{DESIRED_IMAGE_SOURCE}" />

Solution 4 - Javascript

The following approach also works if you want to handle the error in you class:

In your template:

<img [src]='varWithPath' (error) ="onImgError($event)">

In your class:

onImgError(event) { 
    event.target.src = 'assets/path_to_your_placeholder_image.jpg';
}

Solution 5 - Javascript

I've created a custom component that uses a placeholder image if the image is still not loaded or if an error occurs when loading it:

img.component.ts:

import { Component, Input, OnChanges } from '@angular/core';

@Component({
	selector: 'my-img',
	templateUrl: 'img.component.html',
})
export class ImgComponent implements OnChanges {
	@Input() 
	public src: string;
	@Input() 
	public default: string;
	@Input() 
	public alt: string;
	public cached = false;
	public loaded = false;
	public error = false;

	private lastSrc: string;

	constructor() { }

	public ngOnChanges() {
		if (this.src !== this.lastSrc) {
			this.lastSrc = this.src;
			this.loaded = false;
			this.error = false;
			this.cached = this.isCached(this.src);
		}

		if (!this.src) {
			this.error = true;
		}
	}

	public onLoad() {
		this.loaded = true;
	}

	public onError() {
		this.error = true;
	}

	private isCached(url: string): boolean {
		if (!url) {
			return false;
		}

		let image = new Image();
		image.src = url;
		let complete = image.complete;

		// console.log('isCached', complete, url);
		
		return complete;
	}
}

img.component.html:

<ng-container *ngIf="!cached">
	<img 
		*ngIf="!error" 
		[hidden]="!loaded"
		[src]="src" 
		[alt]="alt" 
		(load)="onLoad()" 
		(error)="onError()"
	>
	<img 
		*ngIf="default && (error || !loaded)" 
		[src]="default" 
		[alt]="alt"
	>
</ng-container>

<ng-container *ngIf="cached">
	<img 
		*ngIf="!error" 
		[src]="src" 
		[alt]="alt" 
		(error)="onError()"
	>
	<img 
		*ngIf="default && error" 
		[src]="default" 
		[alt]="alt"
	>
</ng-container>

Then you can use it like:

<my-img [src]="src" [alt]="alt" [default]="DEFAULT_IMAGE"></my-img>

PS: I verify beforehand if the image is cached to avoid the image blinking (normally when a component that has the image inside is re-rendered) between the placeholder and the image (if it is cached, I show the image even before the loaded flag be set to true). You can uncomment the log in the isCached function to see if your images are cached or not.

Solution 6 - Javascript

<img class="thumbnail-image" src="getImage()" alt="...">

getImage():string{  //I don't know how would you handle your situation here. But you can think of it.

  if (this.validImage) // I don't know how would you manage validImage here.
  {
     return this.validImagePath;
  }

   return this.placeholderImagePath;
}

Solution 7 - Javascript

src="validImage ? validImageUrl : placeHolderImgUrl"

Solution 8 - Javascript

I Just did this :

In my HTML FILE wrote this

<div 
   (click)="getInfo(results[movie].id)"
   *ngFor="let movie of (results | key:'10')" 
    class="card" style="margin-top:7%;">
 <img [src]="getImage(results[movie])" alt="" class="card-img-top pointer"></div>

I called a function that is in my component.ts and pass the object wheres my url as a parameter

getImage(result){
if(result.poster_path){
  return this.imageURL+(result.poster_path);
}else return "./assets/noFound.jpg"

Heres my function , first I verify if the object image url is different from null if is true then I return the image url else i return my default "noFound" image that is in my app assets.
Hope it helps!

Attributions

All content for this solution is sourced from the original question on Stackoverflow.

The content on this page is licensed under the Attribution-ShareAlike 4.0 International (CC BY-SA 4.0) license.

Content TypeOriginal AuthorOriginal Content on Stackoverflow
Questionuser2263572View Question on Stackoverflow
Solution 1 - JavascriptJanRView Answer on Stackoverflow
Solution 2 - JavascriptTiago BértoloView Answer on Stackoverflow
Solution 3 - JavascriptChris WheatonView Answer on Stackoverflow
Solution 4 - JavascriptOmarView Answer on Stackoverflow
Solution 5 - JavascriptLucas BasquerottoView Answer on Stackoverflow
Solution 6 - JavascriptNikhil ShahView Answer on Stackoverflow
Solution 7 - Javascriptrobert kingView Answer on Stackoverflow
Solution 8 - JavascriptJared Josafhat H ZView Answer on Stackoverflow