Reputation: 5606
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.
Upvotes: 63
Views: 88782
Reputation: 153
You can use property binding and OR operator to do this without generating a 404 error in the console. Just make sure to provide the exact location for the placeholder image.
<img class="thumbnail-image" [src]="validImage || '/assets/images/placeholder.jpg'" alt="...">
In here, the validImage property should provide the dynamic image. If it's not available, it uses the placeholder image.
Upvotes: 0
Reputation: 1040
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';
}
Upvotes: 19
Reputation: 6132
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="..." />
Upvotes: 175
Reputation: 429
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}" />
Upvotes: 32
Reputation: 169
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!
Upvotes: 0
Reputation: 8073
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.
Upvotes: 4
Reputation: 4343
<img [src]="pic" (error)="setDefaultPic()">
And somewhere in your component class:
setDefaultPic() {
this.pic = "assets/images/my-image.png";
}
Upvotes: 49
Reputation: 55443
<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;
}
Upvotes: 1