Detecting an image 404 in Javascript

59,739

Solution 1

From: http://lucassmith.name/2008/11/is-my-image-loaded.html

// First a couple helper functions
function $(id) {
    return !id || id.nodeType === 1 ? id : document.getElementById(id);
}
function isType(o,t) {    return (typeof o).indexOf(t.charAt(0).toLowerCase()) === 0;}

// Here's the meat and potatoes
function image(src,cfg) {    var img, prop, target;
    cfg = cfg || (isType(src,'o') ? src : {});

    img = $(src);
    if (img) {
        src = cfg.src || img.src;
    } else {
        img = document.createElement('img');
        src = src || cfg.src;
    }

    if (!src) {
        return null;
    }

    prop = isType(img.naturalWidth,'u') ? 'width' : 'naturalWidth';
    img.alt = cfg.alt || img.alt;

    // Add the image and insert if requested (must be on DOM to load or
    // pull from cache)
    img.src = src;

    target = $(cfg.target);
    if (target) {
        target.insertBefore(img, $(cfg.insertBefore) || null);
    }

    // Loaded?
    if (img.complete) {
        if (img[prop]) {
            if (isType(cfg.success,'f')) {
                cfg.success.call(img);
            }
        } else {
            if (isType(cfg.failure,'f')) {
                cfg.failure.call(img);
            }
        }
    } else {
        if (isType(cfg.success,'f')) {
            img.onload = cfg.success;
        }
        if (isType(cfg.failure,'f')) {
            img.onerror = cfg.failure;
        }
    }

    return img;
}

And here how to use it:

image('imgId',{
    success : function () { alert(this.width); },
    failure : function () { alert('Damn your eyes!'); },
});

image('http://somedomain.com/image/typooed_url.jpg', {
    success : function () {...},
    failure : function () {...},
    target : 'myContainerId',
    insertBefore : 'someChildOfmyContainerId'
});

Solution 2

Handle the <img> element's onerror event.

Solution 3

First option:

<img src="picture1.gif" onerror="this.onerror=null;this.src='missing.gif';"/>

Second option:

<html>
<head>
<script type="text/javascript">
    function ImgError(source){
        source.src = "/noimage.gif";
        source.onerror = "";
        return true;
    }
</script>
</head>
<body>
    <img src="image_example1.jpg" onerror="ImgError(this)" />
</body>
</html>

PS: it's pure javascript! you don't need any libraries. (Vanilla JS)

Example in Fidler

https://jsfiddle.net/dorathoto/8z4Ltzp8/71/

Solution 4

just bind the attr trigger on the error event.

$(myimgvar).bind('error',function(ev){
    //error has been thrown
    $(this).attr('src','/path/to/no-artwork-available.jpg');
}).attr('src',urlvar);

Solution 5

This worked for me (mine is in coffeescript). You'll need to replace with a spinner instead, of course.

checkImages = ->
  $("img").each ->
    $(this).error ->
      $(this).attr("src", "../default/image.jpg")

$(document).on('page:load', checkImages)

I'm guessing the javascript equivalent is something like

function checkImages() {
  $("img").each(function() {
    $(this).error(function() {
      $(this).attr("src", "../default/image.jpg");
    });
  });
};

$(document).on("page:load", checkImages);

Share:
59,739
Admin
Author by

Admin

Updated on April 30, 2021

Comments

  • Admin
    Admin about 3 years

    After a user uploads a file we have to do some additional processing with the images such as resizing and upload to S3. This can take up to 10 extra seconds. Obviously we do this in a background. However, we want to show the user the result page immediately and simply show spinners in place until the images arrive in their permanent home on s3.

    I'm looking for a way to detect that a certain image failed to load correctly (404) in a cross browser way. If that happens, we want to use JS to show a spinner in it's place and reload the image every few seconds until it can be successfully loaded from s3.

  • T.J. Crowder
    T.J. Crowder almost 14 years
    @xal: Just be sure to hook the error event before you set the src property (if you're doing this with new Image or document.createElement("img") rather than via an HTML string). Otherwise, you're in a race condition and the event could fire before you start handling it (just like the load event).
  • SLaks
    SLaks almost 14 years
    @T.J: Not necessarily. Javascript runs on the UI thread, so if you handle the event immediately after setting src, there shouldn't be any risk. However, you're still right,
  • SLaks
    SLaks almost 14 years
    This raises a good point. You (OP) need to load the images with random querystring parameters.
  • T.J. Crowder
    T.J. Crowder almost 14 years
    Javascript runs on the Javascript thread, which on some browsers is also the UI thread. It is not necessarily the download thread. I've helped people fix bugs caused by precisely this, setting src before setting a load handler. There's a race condition there. If you already have the handler registered, the event handling code will put it on the execution stack to be run once the JS thread is available to do something else. If you don't, you can miss the event.
  • mxcl
    mxcl about 11 years
    The link died. This answer should be amended to contain content or have it’s green tick taken away.
  • Daniele Vrut
    Daniele Vrut almost 10 years
    KISS (aka Keep It Super Simple)
  • Bangkokian
    Bangkokian over 8 years
    This assumes that all failed loads are 404's.
  • oriadam
    oriadam over 8 years
    I would change the isType function to a simple typeof cfg.x==='function'. It is more readable than 'f', and also faster - see here: jsperf.com/typeof-variations
  • Lukas
    Lukas over 8 years
    Code examples for this: maisonbisson.com/post/12150/…
  • THE JOATMON
    THE JOATMON almost 6 years
    OP specifically said 404.
  • Tyler Roper
    Tyler Roper over 5 years
    I'd like to comment on this, despite it being somewhat dated at this point, simply because it's a pretty popular question and answer. If an <img> returns a 404, but the response includes an image (a placeholder image, for example), the error event will not be fired.
  • tonejac
    tonejac about 5 years
    Rock on, for the 'First Option'. So very light-weight and to the point.
  • Hisagr
    Hisagr over 4 years
    This doesn't work if request returns HTTP 404 and fallback image
  • Dorathoto
    Dorathoto about 4 years
    @tonejac yes..but if you want to put in all the images, I recommend a second option, save the final lines of code and kb.