Reputation: 25928
Is there a way to determine if a image path leads to an actual image, Ie, detect when an image fails to load in JavaScript.
For a web app, I am parsing a xml file and dynamically creating HTML images from a list of image paths. Some image paths may no longer exist on the server so I want to fail gracefully by detecting which images fail to load and deleting that HTML img element.
Note jQuery solutions wont be able to be used(the boss doesn't want to use jQuery, yes I know dont get me started). I know of a way in jQuery to detect when an image is loaded, but not whether it failed.
My code to create img elements but how can I detect if the img path leads to a failed to load image?
var imgObj = new Image(); // document.createElement("img");
imgObj.src = src;
Upvotes: 157
Views: 191586
Reputation: 625
More to the answer of Rafael Martins, if you are using React, use this code:
<img
src="https://example.com/does_not_exist.png"
onError={(e) => {
e.currentTarget.src = "https://example.com/default.png"
}}
/>
Upvotes: 5
Reputation: 1879
This is a variation of @emil.c answer but resolves with true/false based on image loading or not (as opposed to throwing an error when it fails):
function testImage(url) {
if (!url || typeof url !== 'string') return Promise.resolve(false);
return new Promise((resolve) => {
const imgElement = new Image();
imgElement.addEventListener('load', () => resolve(true));
imgElement.addEventListener('error', () => resolve(false));
imgElement.src = url;
});
}
Upvotes: 5
Reputation: 3712
With jQuery this is working for me :
$('img').error(function() {
$(this).attr('src', '/no-img.png').addClass('no-img');
});
And I can use this picture everywhere on my website regardless of the size of it with the following CSS3 property :
img.no-img {
object-fit: cover;
object-position: 50% 50%;
}
TIP 1 : use a square image of at least 800 x 800 pixels.
TIP 2 : for use with portrait of people, use
object-position: 20% 50%;
For missing background images, I also added the following on each background-image
declaration :
background-image: url('path-to-image.png'), url('no-img.png');
NOTE : not working for transparent images.
Another solution is to detect missing image with Apache before to send to browser and remplace it by the default no-img.png content.
RewriteCond %{REQUEST_FILENAME} !-f
RewriteCond %{REQUEST_URI} /images/.*\.(gif|jpg|jpeg|png)$
RewriteRule .* /images/no-img.png [L,R=307]
Upvotes: 7
Reputation: 591
This:
<img onerror="this.src='/images/image.png'" src="...">
Upvotes: 58
Reputation: 2609
/**
* Tests image load.
* @param {String} url
* @returns {Promise}
*/
function testImageUrl(url) {
return new Promise(function(resolve, reject) {
var image = new Image();
image.addEventListener('load', resolve);
image.addEventListener('error', reject);
image.src = url;
});
}
return testImageUrl(imageUrl).then(function imageLoaded(e) {
return imageUrl;
})
.catch(function imageFailed(e) {
return defaultImageUrl;
});
Upvotes: 11
Reputation: 2018
The answer is nice, but it introduces one problem. Whenever you assign onload
or onerror
directly, it may replace the callback that was assigned earlier. That is why there's a nice method that "registers the specified listener on the EventTarget it's called on" as they say on MDN. You can register as many listeners as you want on the same event.
Let me rewrite the answer a little bit.
function testImage(url) {
var tester = new Image();
tester.addEventListener('load', imageFound);
tester.addEventListener('error', imageNotFound);
tester.src = url;
}
function imageFound() {
alert('That image is found and loaded');
}
function imageNotFound() {
alert('That image was not found.');
}
testImage("http://foo.com/bar.jpg");
Because the external resource loading process is asynchronous, it would be even nicer to use modern JavaScript with promises, such as the following.
function testImage(url) {
// Define the promise
const imgPromise = new Promise(function imgPromise(resolve, reject) {
// Create the image
const imgElement = new Image();
// When image is loaded, resolve the promise
imgElement.addEventListener('load', function imgOnLoad() {
resolve(this);
});
// When there's an error during load, reject the promise
imgElement.addEventListener('error', function imgOnError() {
reject();
})
// Assign URL
imgElement.src = url;
});
return imgPromise;
}
testImage("http://foo.com/bar.jpg").then(
function fulfilled(img) {
console.log('That image is found and loaded', img);
},
function rejected() {
console.log('That image was not found');
}
);
Upvotes: 73
Reputation: 3152
You could try the following code. I can't vouch for browser compatibility though, so you'll have to test that.
function testImage(URL) {
var tester=new Image();
tester.onload=imageFound;
tester.onerror=imageNotFound;
tester.src=URL;
}
function imageFound() {
alert('That image is found and loaded');
}
function imageNotFound() {
alert('That image was not found.');
}
testImage("http://foo.com/bar.jpg");
And my sympathies for the jQuery-resistant boss!
Upvotes: 165
Reputation: 12
just like below:
var img = new Image();
img.src = imgUrl;
if (!img.complete) {
//has picture
}
else //not{
}
Upvotes: -21
Reputation: 707158
Here's a function I wrote for another answer: Javascript Image Url Verify. I don't know if it's exactly what you need, but it uses the various techniques that you would use which include handlers for onload
, onerror
, onabort
and a general timeout.
Because image loading is asynchronous, you call this function with your image and then it calls your callback sometime later with the result.
Upvotes: 3