Angular 2 - Check if image url is valid or broken

JavascriptAngular

Javascript Problem Overview


I am fetching a large number of image URLs from an API and display them in a angular 2 web application. Some of the URLs are broken and i want to replace them with a default picture that is stored locally on my webserver. Does anyone have a suggestion how to test the urls and in the case of status code 404 replace the broken image?

Thanks!

Javascript Solutions


Solution 1 - Javascript

Listen to the error event of the image element:

<img [src]="someUrl" (error)="updateUrl($event)">

where updateUrl(event) { ... } assigns a new value to this.someUrl.

Plunker example

If you want to check in code only you can use the method explained in https://stackoverflow.com/questions/14651348/checking-if-image-does-exists-using-javascript

@Directive({
  selector: 'img[default]',
  host: {
    '(error)':'updateUrl()',
    '[src]':'src'
   }
})
class DefaultImage {
  @Input() src:string;
  @Input() default:string;

  updateUrl() {
    this.src = this.default;
  }
}

Directive Plunker example

Solution 2 - Javascript

You can use onError event this way to handle invalid url or broken url.

<img [src]="invalidPath" onError="this.src='images/angular.png'"/> 

This way you can directly assign img path to src with onError event

Solution 3 - Javascript

My example on angular 4

<img [src]="img" (error)="img.src = errorImg" #img>
  1. Where img - path to image;
  2. error - error emmit
  3. errorImg - path to default img
  4. #img - link to img object

Solution 4 - Javascript

I use a base64 loading spinner:

<img [src]="photoContainer.photo.url | secure" onError="this.src='data:image/svg+xml;base64,PD94bWwgdmVyc2lvbj0iMS4wIiBzdGFuZGFsb25lPSJubyI/Pgo8IURPQ1RZUEUgc3ZnIFBVQkxJQyAiLS8vVzNDLy9EVEQgU1ZHIDEuMS8vRU4iICJodHRwOi8vd3d3LnczLm9yZy9HcmFwaGljcy9TVkcvMS4xL0RURC9zdmcxMS5kdGQiPgo8c3ZnIHdpZHRoPSI0MHB4IiBoZWlnaHQ9IjQwcHgiIHZpZXdCb3g9IjAgMCA0MCA0MCIgdmVyc2lvbj0iMS4xIiB4bWxucz0iaHR0cDovL3d3dy53My5vcmcvMjAwMC9zdmciIHhtbG5zOnhsaW5rPSJodHRwOi8vd3d3LnczLm9yZy8xOTk5L3hsaW5rIiB4bWw6c3BhY2U9InByZXNlcnZlIiBzdHlsZT0iZmlsbC1ydWxlOmV2ZW5vZGQ7Y2xpcC1ydWxlOmV2ZW5vZGQ7c3Ryb2tlLWxpbmVqb2luOnJvdW5kO3N0cm9rZS1taXRlcmxpbWl0OjEuNDE0MjE7IiB4PSIwcHgiIHk9IjBweCI+CiAgICA8ZGVmcz4KICAgICAgICA8c3R5bGUgdHlwZT0idGV4dC9jc3MiPjwhW0NEQVRBWwogICAgICAgICAgICBALXdlYmtpdC1rZXlmcmFtZXMgc3BpbiB7CiAgICAgICAgICAgICAgZnJvbSB7CiAgICAgICAgICAgICAgICAtd2Via2l0LXRyYW5zZm9ybTogcm90YXRlKDBkZWcpCiAgICAgICAgICAgICAgfQogICAgICAgICAgICAgIHRvIHsKICAgICAgICAgICAgICAgIC13ZWJraXQtdHJhbnNmb3JtOiByb3RhdGUoLTM1OWRlZykKICAgICAgICAgICAgICB9CiAgICAgICAgICAgIH0KICAgICAgICAgICAgQGtleWZyYW1lcyBzcGluIHsKICAgICAgICAgICAgICBmcm9tIHsKICAgICAgICAgICAgICAgIHRyYW5zZm9ybTogcm90YXRlKDBkZWcpCiAgICAgICAgICAgICAgfQogICAgICAgICAgICAgIHRvIHsKICAgICAgICAgICAgICAgIHRyYW5zZm9ybTogcm90YXRlKC0zNTlkZWcpCiAgICAgICAgICAgICAgfQogICAgICAgICAgICB9CiAgICAgICAgICAgIHN2ZyB7CiAgICAgICAgICAgICAgICAtd2Via2l0LXRyYW5zZm9ybS1vcmlnaW46IDUwJSA1MCU7CiAgICAgICAgICAgICAgICAtd2Via2l0LWFuaW1hdGlvbjogc3BpbiAxLjVzIGxpbmVhciBpbmZpbml0ZTsKICAgICAgICAgICAgICAgIC13ZWJraXQtYmFja2ZhY2UtdmlzaWJpbGl0eTogaGlkZGVuOwogICAgICAgICAgICAgICAgYW5pbWF0aW9uOiBzcGluIDEuNXMgbGluZWFyIGluZmluaXRlOwogICAgICAgICAgICB9CiAgICAgICAgXV0+PC9zdHlsZT4KICAgIDwvZGVmcz4KICAgIDxnIGlkPSJvdXRlciI+CiAgICAgICAgPGc+CiAgICAgICAgICAgIDxwYXRoIGQ9Ik0yMCwwQzIyLjIwNTgsMCAyMy45OTM5LDEuNzg4MTMgMjMuOTkzOSwzLjk5MzlDMjMuOTkzOSw2LjE5OTY4IDIyLjIwNTgsNy45ODc4MSAyMCw3Ljk4NzgxQzE3Ljc5NDIsNy45ODc4MSAxNi4wMDYxLDYuMTk5NjggMTYuMDA2MSwzLjk5MzlDMTYuMDA2MSwxLjc4ODEzIDE3Ljc5NDIsMCAyMCwwWiIgc3R5bGU9ImZpbGw6YmxhY2s7Ii8+CiAgICAgICAgPC9nPgogICAgICAgIDxnPgogICAgICAgICAgICA8cGF0aCBkPSJNNS44NTc4Niw1Ljg1Nzg2QzcuNDE3NTgsNC4yOTgxNSA5Ljk0NjM4LDQuMjk4MTUgMTEuNTA2MSw1Ljg1Nzg2QzEzLjA2NTgsNy40MTc1OCAxMy4wNjU4LDkuOTQ2MzggMTEuNTA2MSwxMS41MDYxQzkuOTQ2MzgsMTMuMDY1OCA3LjQxNzU4LDEzLjA2NTggNS44NTc4NiwxMS41MDYxQzQuMjk4MTUsOS45NDYzOCA0LjI5ODE1LDcuNDE3NTggNS44NTc4Niw1Ljg1Nzg2WiIgc3R5bGU9ImZpbGw6cmdiKDIxMCwyMTAsMjEwKTsiLz4KICAgICAgICA8L2c+CiAgICAgICAgPGc+CiAgICAgICAgICAgIDxwYXRoIGQ9Ik0yMCwzMi4wMTIyQzIyLjIwNTgsMzIuMDEyMiAyMy45OTM5LDMzLjgwMDMgMjMuOTkzOSwzNi4wMDYxQzIzLjk5MzksMzguMjExOSAyMi4yMDU4LDQwIDIwLDQwQzE3Ljc5NDIsNDAgMTYuMDA2MSwzOC4yMTE5IDE2LjAwNjEsMzYuMDA2MUMxNi4wMDYxLDMzLjgwMDMgMTcuNzk0MiwzMi4wMTIyIDIwLDMyLjAxMjJaIiBzdHlsZT0iZmlsbDpyZ2IoMTMwLDEzMCwxMzApOyIvPgogICAgICAgIDwvZz4KICAgICAgICA8Zz4KICAgICAgICAgICAgPHBhdGggZD0iTTI4LjQ5MzksMjguNDkzOUMzMC4wNTM2LDI2LjkzNDIgMzIuNTgyNCwyNi45MzQyIDM0LjE0MjEsMjguNDkzOUMzNS43MDE5LDMwLjA1MzYgMzUuNzAxOSwzMi41ODI0IDM0LjE0MjEsMzQuMTQyMUMzMi41ODI0LDM1LjcwMTkgMzAuMDUzNiwzNS43MDE5IDI4LjQ5MzksMzQuMTQyMUMyNi45MzQyLDMyLjU4MjQgMjYuOTM0MiwzMC4wNTM2IDI4LjQ5MzksMjguNDkzOVoiIHN0eWxlPSJmaWxsOnJnYigxMDEsMTAxLDEwMSk7Ii8+CiAgICAgICAgPC9nPgogICAgICAgIDxnPgogICAgICAgICAgICA8cGF0aCBkPSJNMy45OTM5LDE2LjAwNjFDNi4xOTk2OCwxNi4wMDYxIDcuOTg3ODEsMTcuNzk0MiA3Ljk4NzgxLDIwQzcuOTg3ODEsMjIuMjA1OCA2LjE5OTY4LDIzLjk5MzkgMy45OTM5LDIzLjk5MzlDMS43ODgxMywyMy45OTM5IDAsMjIuMjA1OCAwLDIwQzAsMTcuNzk0MiAxLjc4ODEzLDE2LjAwNjEgMy45OTM5LDE2LjAwNjFaIiBzdHlsZT0iZmlsbDpyZ2IoMTg3LDE4NywxODcpOyIvPgogICAgICAgIDwvZz4KICAgICAgICA8Zz4KICAgICAgICAgICAgPHBhdGggZD0iTTUuODU3ODYsMjguNDkzOUM3LjQxNzU4LDI2LjkzNDIgOS45NDYzOCwyNi45MzQyIDExLjUwNjEsMjguNDkzOUMxMy4wNjU4LDMwLjA1MzYgMTMuMDY1OCwzMi41ODI0IDExLjUwNjEsMzQuMTQyMUM5Ljk0NjM4LDM1LjcwMTkgNy40MTc1OCwzNS43MDE5IDUuODU3ODYsMzQuMTQyMUM0LjI5ODE1LDMyLjU4MjQgNC4yOTgxNSwzMC4wNTM2IDUuODU3ODYsMjguNDkzOVoiIHN0eWxlPSJmaWxsOnJnYigxNjQsMTY0LDE2NCk7Ii8+CiAgICAgICAgPC9nPgogICAgICAgIDxnPgogICAgICAgICAgICA8cGF0aCBkPSJNMzYuMDA2MSwxNi4wMDYxQzM4LjIxMTksMTYuMDA2MSA0MCwxNy43OTQyIDQwLDIwQzQwLDIyLjIwNTggMzguMjExOSwyMy45OTM5IDM2LjAwNjEsMjMuOTkzOUMzMy44MDAzLDIzLjk5MzkgMzIuMDEyMiwyMi4yMDU4IDMyLjAxMjIsMjBDMzIuMDEyMiwxNy43OTQyIDMzLjgwMDMsMTYuMDA2MSAzNi4wMDYxLDE2LjAwNjFaIiBzdHlsZT0iZmlsbDpyZ2IoNzQsNzQsNzQpOyIvPgogICAgICAgIDwvZz4KICAgICAgICA8Zz4KICAgICAgICAgICAgPHBhdGggZD0iTTI4LjQ5MzksNS44NTc4NkMzMC4wNTM2LDQuMjk4MTUgMzIuNTgyNCw0LjI5ODE1IDM0LjE0MjEsNS44NTc4NkMzNS43MDE5LDcuNDE3NTggMzUuNzAxOSw5Ljk0NjM4IDM0LjE0MjEsMTEuNTA2MUMzMi41ODI0LDEzLjA2NTggMzAuMDUzNiwxMy4wNjU4IDI4LjQ5MzksMTEuNTA2MUMyNi45MzQyLDkuOTQ2MzggMjYuOTM0Miw3LjQxNzU4IDI4LjQ5MzksNS44NTc4NloiIHN0eWxlPSJmaWxsOnJnYig1MCw1MCw1MCk7Ii8+CiAgICAgICAgPC9nPgogICAgPC9nPgo8L3N2Zz4K'">

Solution 5 - Javascript

I found a very simple solution that worked for me. This doesn't check for 404's however I had objects that possibly had and .image attribute. I know this isn't the answer to his question but hopefully it helps some one out there.

<img class="list-thumb-img" [attr.src]="item.image?.url ? item.image.url : 'assets/img/140-100.png'">

Solution 6 - Javascript

A perfect Angular 8 directive:

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

@Directive({
    selector: '[appImage]'
})
export class ImageDirective implements AfterViewInit {

    @Input() src;

    constructor(private imageRef: ElementRef) {
    }

    ngAfterViewInit(): void {
        const img = new Image();
        img.onload = () => {
            this.setImage(this.src);
        };

        img.onerror = () => {
            // Set a placeholder image 
            this.setImage('assets/placeholder.png');
        };

        img.src = this.src;
    }

    private setImage(src: string) {
        this.imageRef.nativeElement.setAttribute('src', src);
    }
}

Now, HTML will be:

<img [src]="'/some/valid-image.png'" appImage>

Solution 7 - Javascript

If you want to change an image that is not loading or the source is broken... Angular 8, just have to change the src of this target for a default asset:

  • Component HTML

    ><... [src]="person.pictureUrl" (error)="pictNotLoading($event)" >

  • Component TS

    >pictNotLoading(event) { event.target.src = 'assets/nopicture.png'; }

Solution 8 - Javascript

this is my solution for fallback on multi images. we basically detach the ChangeDetector once we resolve the image so we can reduce CPU on vm check cycles once image is resolved.

import {Component, ChangeDetectionStrategy, ChangeDetectorRef} from 'angular2/core';
import {AppStore} from "angular2-redux-util/dist/index";



@Component({
    selector: 'logoCompany',
    changeDetection: ChangeDetectionStrategy.Default,
    template: `
            <div style="padding-top: 7px" > 
              <span style="color: gainsboro; font-family: Roboto">{{getBusinessInfo('companyName')}}</span>
              <!--<img style="width: 35px" class="img-circle" src="http://galaxy.example.me/Resources/Resellers/{{getBusinessInfo('businessId')}}/{{getBusinessInfo('fileName')}}" />-->
              <img style="width: 35px" class="img-circle" [src]="getImageUrl()" (load)="onImageLoaded()" (error)="onImageError()" />
            </div>
    `
})

export class LogoCompany {

    constructor(private cdr:ChangeDetectorRef) {    
    }
    private imageRetries:number = 0;
    private unsub;


    private detach() {
        this.cdr.detach();
    }

    private getImageUrl() {          
        var url = '';
        switch (this.imageRetries){
            case 0: {
                url = 'http://galaxy.example.me/Resources/Resellers/' + this.getBusinessInfo('businessId') + '/Logo.jpg'
                break;
            }
            case 1: {
                url = 'http://galaxy.example.me/Resources/Resellers/' + this.getBusinessInfo('businessId') + '/Logo.png'
                break;
            }
            default: {
                url = 'assets/person.png'
                break;
            }

        }
        return url;
    }

    private onImageLoaded() {
        this.detach();
    }

    private onImageError() {
        this.imageRetries++;
    }

    private getBusinessInfo(field):string {
          return '12345';
    }

 
 


}

Solution 9 - Javascript

The event of error happen only if the url is not correct, if the url is correct but the file is not exists you can use in this code

javascript check if file exists on server:

(Note that the 404 is a number and not a string)

function doesFileExist(urlToFile) {
var xhr = new XMLHttpRequest();
xhr.open('HEAD', urlToFile, false);
xhr.send();
 
if (xhr.status == 404) {
    return false;
} else {
    return true;
}}

Solution 10 - Javascript

You can simply use a ternary operator for this use case. I am assuming that you are getting the responses from a remote server

<img src="{{ res.image ? res.image : onErrorFunction() }}"

If you don't want to have the image from server write the path in single quotes ''.

Here if the link is broken then it will go to onErrorFunction if it isn't broken the res.image will be loaded.

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
QuestionJakob SvenningssonView Question on Stackoverflow
Solution 1 - JavascriptGünter ZöchbauerView Answer on Stackoverflow
Solution 2 - JavascriptmicronyksView Answer on Stackoverflow
Solution 3 - JavascriptsergamersView Answer on Stackoverflow
Solution 4 - Javascriptrobert kingView Answer on Stackoverflow
Solution 5 - JavascriptdoneDoneView Answer on Stackoverflow
Solution 6 - JavascriptShashank AgrawalView Answer on Stackoverflow
Solution 7 - JavascriptIng Guillermo MalagónView Answer on Stackoverflow
Solution 8 - Javascriptborn2netView Answer on Stackoverflow
Solution 9 - JavascriptNir AmirView Answer on Stackoverflow
Solution 10 - JavascriptChirag JainView Answer on Stackoverflow