I have a web page that includes a bunch of images. Sometimes the image isn\'t available, so a broken image is displayed in the client\'s browser.
How do I use jQuery
In case someone like me, tries to attach the error
event to a dynamic HTML img
tag, I'd like to point out that, there is a catch:
Apparently img
error events don't bubble in most browsers, contrary to what the standard says.
So, something like the following will not work:
$(document).on('error', 'img', function () { ... })
Hope this will be helpful to someone else. I wish I had seen this here in this thread. But, I didn't. So, I am adding it
While the OP was looking to replace the SRC, I'm sure many people hitting this question may only wish to hide the broken image, in which case this simple solution worked great for me.
<img src="img.jpg" onerror="this.style.display='none';" />
var images = document.querySelectorAll('img');
for (var i = 0; i < images.length; i++) {
images[i].onerror = function() {
this.style.display='none';
}
}
<img src='img.jpg' />
document.querySelectorAll('img').forEach((img) => {
img.onerror = function() {
this.style.display = 'none';
}
});
<img src='img.jpg' />
See browser support for NodeList.forEach and arrow functions.
I solved my problem with these two simple functions:
function imgExists(imgPath) {
var http = jQuery.ajax({
type:"HEAD",
url: imgPath,
async: false
});
return http.status != 404;
}
function handleImageError() {
var imgPath;
$('img').each(function() {
imgPath = $(this).attr('src');
if (!imgExists(imgPath)) {
$(this).attr('src', 'images/noimage.jpg');
}
});
}
This is a crappy technique, but it's pretty much guaranteed:
<img onerror="this.parentNode.removeChild(this);">
I couldn't find a script to suit my needs, so I made a recursive function to check for broken images and attempt to reload them every four seconds until they are fixed.
I limited it to 10 attempts as if it's not loaded by then the image might not be present on server and the function would enter an infinite loop. I am still testing though. Feel free to tweak it :)
var retries = 0;
$.imgReload = function() {
var loaded = 1;
$("img").each(function() {
if (!this.complete || typeof this.naturalWidth == "undefined" || this.naturalWidth == 0) {
var src = $(this).attr("src");
var date = new Date();
$(this).attr("src", src + "?v=" + date.getTime()); //slightly change url to prevent loading from cache
loaded =0;
}
});
retries +=1;
if (retries < 10) { // If after 10 retries error images are not fixed maybe because they
// are not present on server, the recursion will break the loop
if (loaded == 0) {
setTimeout('$.imgReload()',4000); // I think 4 seconds is enough to load a small image (<50k) from a slow server
}
// All images have been loaded
else {
// alert("images loaded");
}
}
// If error images cannot be loaded after 10 retries
else {
// alert("recursion exceeded");
}
}
jQuery(document).ready(function() {
setTimeout('$.imgReload()',5000);
});
You can use GitHub's own fetch for this:
Frontend: https://github.com/github/fetch
or for Backend, a Node.js version: https://github.com/bitinn/node-fetch
fetch(url)
.then(function(res) {
if (res.status == '200') {
return image;
} else {
return placeholder;
}
}
Edit: This method is going to replace XHR and supposedly already has been in Chrome. To anyone reading this in the future, you may not need the aforementioned library included.