I'm trying to update my image source using jquery. To do it, I am calling .load
function that will return a string which in turn will be used to replace the image source.
srcResult value is new/icon.png:
<script>
var iconLinkURL = "Users/NewIcon";
var srcResult = $("#iconImage").children('img').load(iconLinkURL);
$("#iconImage").children('img').attr('src', srcResult);
</script>
HTML Side
<a id="iconImage"><img src="old/address.png"></img></a>
What happens is that when the javascript is loaded, the image is loaded like this:
<a id="iconImage"><img src="[object Object]">new/icon.png</img></a>
Am I missing something hence the issue is persisting?
load() returns an object. If you're not interested in pre-loading, just replace your code as follows:
$("#iconImage").children('img').prop('src', 'Users/NewIcon');
However, if you wish to preload the image, use the following:
var src = 'Users/NewIcon',
img = new Image();
img.src = src;
img.onload = function() {
$('#iconImage').children('img').prop('src', this.src);
};
It's worth noting that you will also need to wrap your code in the DOMReady event if you're not doing that already.
I'm using JavaScript with the jQuery library to manipulate image thumbnails contained in a unordered list. When the image is loaded it does one thing, when an error occurs it does something else. I'm using jQuery load() and error() methods as events. After these events I check the image DOM element for the .complete to make sure the image wasn't already loaded before jQuery could register the events.
It works correctly except when an error occurs before jQuery can register the events. The only solution I can think of is to use the img onerror attribute to store a "flag" somewhere globally (or on the node it's self) that says it failed so jQuery can check that "store/node" when checking .complete.
Anyone have a better solution?
Edit: Bolded main points and added extra detail below:
I'm checking if an image is complete (aka loaded) AFTER I add a load and error event on the image. That way, if the image was loaded before the events were registered, I will still know. If the image isn't loaded after the events then the events will take care of it when it does. The problem with this is, I can easily check if an image is loaded already, but I can't tell if an error occurred instead.
Check the complete and naturalWidth properties, in that order.
https://stereochro.me/ideas/detecting-broken-images-js
function IsImageOk(img) {
// During the onload event, IE correctly identifies any images that
// weren’t downloaded as not complete. Others should too. Gecko-based
// browsers act like NS4 in that they report this incorrectly.
if (!img.complete) {
return false;
}
// However, they do have two very useful properties: naturalWidth and
// naturalHeight. These give the true size of the image. If it failed
// to load, either of these should be zero.
if (img.naturalWidth === 0) {
return false;
}
// No other way of checking: assume it’s ok.
return true;
}
Another option is to trigger the onload and/or onerror events by creating an in memory image element and setting its src attribute to the original src attribute of the original image. Here's an example of what I mean:
$("<img/>")
.on('load', function() { console.log("image loaded correctly"); })
.on('error', function() { console.log("error loading image"); })
.attr("src", $(originalImage).attr("src"))
;
Based on my understanding of the W3C HTML Specification for the img element, you should be able to do this using a combination of the complete and naturalHeight attributes, like so:
function imgLoaded(imgElement) {
return imgElement.complete && imgElement.naturalHeight !== 0;
}
From the spec for the complete attribute:
The IDL attribute complete must return true if any of the following
conditions is true:
The src attribute is omitted.
The final task that is queued by the networking task source once the resource has been fetched has been queued.
The img element is completely available.
The img element is broken.
Otherwise, the attribute must return false.
So essentially, complete returns true if the image has either finished loading, or failed to load. Since we want only the case where the image successfully loaded we need to check the nauturalHeight attribute as well:
The IDL attributes naturalWidth and naturalHeight must return the
intrinsic width and height of the image, in CSS pixels, if the image
is available, or else 0.
And available is defined like so:
An img is always in one of the following states:
Unavailable - The user agent hasn't obtained any image data.
Partially available - The user agent has obtained some of the image data.
Completely available - The user agent has obtained all of the image data and at least the image dimensions are available.
Broken - The user agent has obtained all of the image data that it can, but it cannot even decode the image enough to get the image
dimensions (e.g. the image is corrupted, or the format is not
supported, or no data could be obtained).
When an img element is either in the partially available state or in
the completely available state, it is said to be available.
So if the image is "broken" (failed to load), then it will be in the broken state, not the available state, so naturalHeight will be 0.
Therefore, checking imgElement.complete && imgElement.naturalHeight !== 0 should tell us whether the image has successfully loaded.
You can read more about this in the W3C HTML Specification for the img element, or on MDN.
I tried many different ways and this way is the only one worked for me
//check all images on the page
$('img').each(function(){
var img = new Image();
img.onload = function() {
console.log($(this).attr('src') + ' - done!');
}
img.src = $(this).attr('src');
});
You could also add a callback function triggered once all images are loaded in the DOM and ready. This applies for dynamically added images too. http://jsfiddle.net/kalmarsh80/nrAPk/
Use imagesLoaded javascript library.
Usable with plain Javascript and as a jQuery plugin.
Features:
officially supported by IE8+
license: MIT
dependencies: none
weight (minified & gzipped) : 7kb minified (light!)
Resources
Project on github: https://github.com/desandro/imagesloaded
Official website: http://imagesloaded.desandro.com/
https://stackoverflow.com/questions/26927575/why-use-imagesloaded-javascript-library-versus-jquerys-window-load
imagesloaded javascript library: what is the browser & device support?
Retrieve informations from image elements on the page
Test working on Chrome and Firefox
Working jsFiddle (open your console to see the result)
$('img').each(function(){ // selecting all image element on the page
var img = new Image($(this)); // creating image element
img.onload = function() { // trigger if the image was loaded
console.log($(this).attr('src') + ' - done!');
}
img.onerror = function() { // trigger if the image wasn't loaded
console.log($(this).attr('src') + ' - error!');
}
img.onAbort = function() { // trigger if the image load was abort
console.log($(this).attr('src') + ' - abort!');
}
img.src = $(this).attr('src'); // pass src to image object
// log image attributes
console.log(img.src);
console.log(img.width);
console.log(img.height);
console.log(img.complete);
});
Note : I used jQuery, I thought this can be acheive on full javascript
I find good information here OpenClassRoom --> this is a French forum
After reading the interesting solutions on this page, I created an easy-to-use solution highly influenced by SLaks' and Noyo's post that seems to be working on pretty recent versions (as of writing) of Chrome, IE, Firefox, Safari, and Opera (all on Windows). Also, it worked on an iPhone/iPad emulator I used.
One major difference between this solution and SLaks and Noyo's post is that this solution mainly checks the naturalWidth and naturalHeight properties. I've found that in the current browser versions, those two properties seem to provide the most helpful and consistent results.
This code returns TRUE when an image has loaded fully AND successfully. It returns FALSE when an image either has not loaded fully yet OR has failed to load.
One thing you will need to be aware of is that this function will also return FALSE if the image is a 0x0 pixel image. But those images are quite uncommon, and I can't think of a very useful case where you would want to check to see if a 0x0 pixel image has loaded yet :)
First we attach a new function called "isLoaded" to the HTMLImageElement prototype, so that the function can be used on any image element.
HTMLImageElement.prototype.isLoaded = function() {
// See if "naturalWidth" and "naturalHeight" properties are available.
if (typeof this.naturalWidth == 'number' && typeof this.naturalHeight == 'number')
return !(this.naturalWidth == 0 && this.naturalHeight == 0);
// See if "complete" property is available.
else if (typeof this.complete == 'boolean')
return this.complete;
// Fallback behavior: return TRUE.
else
return true;
};
Then, any time we need to check the loading status of the image, we just call the "isLoaded" function.
if (someImgElement.isLoaded()) {
// YAY! The image loaded
}
else {
// Image has not loaded yet
}
Per giorgian's comment on SLaks' and Noyo's post, this solution probably can only be used as a one-time check on Safari Mobile if you plan on changing the SRC attribute. But you can work around that by creating an image element with a new SRC attribute instead of changing the SRC attribute on an existing image element.
Realtime network detector - check network status without refreshing the page:
(it's not jquery, but tested, and 100% works:(tested on Firefox v25.0))
Code:
<script>
function ImgLoad(myobj){
var randomNum = Math.round(Math.random() * 10000);
var oImg=new Image;
oImg.src="YOUR_IMAGELINK"+"?rand="+randomNum;
oImg.onload=function(){alert('Image succesfully loaded!')}
oImg.onerror=function(){alert('No network connection or image is not available.')}
}
window.onload=ImgLoad();
</script>
<button id="reloadbtn" onclick="ImgLoad();">Again!</button>
if connection lost just press the Again button.
Update 1:
Auto detect without refreshing the page:
<script>
function ImgLoad(myobj){
var randomNum = Math.round(Math.random() * 10000);
var oImg=new Image;
oImg.src="YOUR_IMAGELINK"+"?rand="+randomNum;
oImg.onload=function(){networkstatus_div.innerHTML="";}
oImg.onerror=function(){networkstatus_div.innerHTML="Service is not available. Please check your Internet connection!";}
}
networkchecker = window.setInterval(function(){window.onload=ImgLoad()},1000);
</script>
<div id="networkstatus_div"></div>
This is how I got it to work cross browser using a combination of the methods above (I also needed to insert images dynamically into the dom):
$('#domTarget').html('<img src="" />');
var url = '/some/image/path.png';
$('#domTarget img').load(function(){}).attr('src', url).error(function() {
if ( isIE ) {
var thisImg = this;
setTimeout(function() {
if ( ! thisImg.complete ) {
$(thisImg).attr('src', '/web/css/img/picture-broken-url.png');
}
},250);
} else {
$(this).attr('src', '/web/css/img/picture-broken-url.png');
}
});
Note: You will need to supply a valid boolean state for the isIE variable.
var isImgLoaded = function(imgSelector){
return $(imgSelector).prop("complete") && $(imgSelector).prop("naturalWidth") !== 0;
}
// Or As a Plugin
$.fn.extend({
isLoaded: function(){
return this.prop("complete") && this.prop("naturalWidth") !== 0;
}
})
// $(".myImage").isLoaded()
As I understand the .complete property is non-standard. It may not be universal... I notice it seem to work differently in Firefox verses IE. I am loading a number of images in javascript then checking if complete. In Firefox, this seems to work great. In IE, it doesn't because the images appear to be loading on another thread. It works only if I put a delay between my assignment to image.src and when I check the image.complete property.
Using image.onload and image.onerror isn't working for me, either, because I need to pass a parameter to know which image I am talking about when the function is called. Any way of doing that seems to fail because it actually seems to pass the same function, not different instances of the same function. So the value I pass into it to identify the image always ends up being the last value in the loop. I cannot think of any way around this problem.
On Safari and Chrome, I am seeing the image.complete true and the naturalWidth set even when the error console shows a 404 for that image... and I intentionally removed that image to test this. But the above works well for Firefox and IE.
This snippet of code helped me to fix browser caching problems:
$("#my_image").on('load', function() {
console.log("image loaded correctly");
}).each(function() {
if($(this).prop('complete')) $(this).load();
});
When the browser cache is disabled, only this code doesn't work:
$("#my_image").on('load', function() {
console.log("image loaded correctly");
})
to make it work you have to add:
.each(function() {
if($(this).prop('complete')) $(this).load();
});
Using this JavaScript code you can check image is successfully loaded or not.
document.onready = function(e) {
var imageobj = new Image();
imageobj.src = document.getElementById('img-id').src;
if(!imageobj.complete){
alert(imageobj.src+" - Not Found");
}
}
Try out this
I had a lot of problems with the complete load of a image and the EventListener.
Whatever I tried, the results was not reliable.
But then I found the solution. It is technically not a nice one, but now I never had a failed image load.
What I did:
document.getElementById(currentImgID).addEventListener("load", loadListener1);
document.getElementById(currentImgID).addEventListener("load", loadListener2);
function loadListener1()
{
// Load again
}
function loadListener2()
{
var btn = document.getElementById("addForm_WithImage"); btn.disabled = false;
alert("Image loaded");
}
Instead of loading the image one time, I just load it a second time direct after the first time and both run trough the eventhandler.
All my headaches are gone!
By the way:
You guys from stackoverflow helped me already more then hundred times. For this a very big Thank you!
This one worked fine for me :)
$('.progress-image').each(function(){
var img = new Image();
img.onload = function() {
let imgSrc = $(this).attr('src');
$('.progress-image').each(function(){
if($(this).attr('src') == imgSrc){
console.log($(this).parent().closest('.real-pack').parent().find('.shimmer').fadeOut())
}
})
}
img.src = $(this).attr('src');
});
I have script that I would like visitors on my website to run when they load a web page. It looks like this:
window.onload = function(){
var pxl=document.createElement('img');
pxl.setAttribute('src', 'http://localhost:8080/getTrackingPixel')
document.body.appendChild(pxl);
}
Most of the times the source returns an image and it works fine. However, sometimes it returns this:
<html><body style="background-color:transparent"></body></html>
And I can't really change the fact that it might sometimes not return an image. How do I change the javascript so that it can handle the html response without any errors? It might be possible for me to predict when it happens though - but I haven't managed to find a good way to request the source and return the html either.
You can achieve it by using the javascript Image object which, unlike the createElement approach, allows you to fetch the src url before inserting the img in the DOM.
The onload event of the Image object won't fire if the loaded content isn't an img.
Here it is :
window.onload = function(){
var pxl = new Image();
pxl.onload = function(){
// is IMG
document.body.appendChild(pxl);
}
pxl.onerror = function(){
// is not IMG
// Meaning in your case : <html><body style="background-color:transparent"></body></html>
}
pxl.src = 'http://localhost:8080/getTrackingPixel';
}
(Note that your code also missed the semicolon ";" line 4)
function swapImg(imgId) {
var image = document.getElementById(imgId);
if (image.getAttribute("class") == "unselected") {
image.setAttribute("src", "img/frownie.gif");
console.log(image);
}
}
if i look at what's outputted to console, the src of the image is correct. but it's not changing in my browser. what's up? (ie, the image stays the same even though the source url is changing...)
I would write your function this way, this should also take care of your error:
function swapImg(imgId) {
var image = document.getElementById(imgId);
if (image.className == "unselected") {
image.src = 'img/frownie.gif';
console.log(image);
}
}
ugh i'm dumb. i accidentally wrote id instead of class in my code so there are multiple images with the same id, which meant i found the first one and swapped it and not the others. thanks for trying :(
I'm using the following code to insert some HTML into a div, and to preload any images that might be contained in that HTML (the html var's data is actually fetched from an AJAX request in the real code). This is to prevent the browser from loading the fetched HTML's images upon showing the div (using the slideDown event) - because this results in the effect's fluidity being broken as it loads image mid-transition. I suppose I could use an interlaced JPEG so that the dimensions of the image are known almost immediately, but obviously it'd be nice to get a cleaner method worked out. :P
var html = '<img src="images/test.jpg" alt="test" />';
$('div.content').hide().html(html);
$('div.content img').each(function(){
var img = new Image();
img.src = $(this).attr('src');
$(this).attr('src', img.src);
});
$('div.content').slideDown('normal');
I'm using the Image object and its subsequent assigning as per the advice given here, but unfortunately the image still isn't cached by the browser using this method, because the sildeDown() effect is still interrupted as the image loads.
Any help or alternative methods? Many thanks.
Edit - 21st Sept 09
Progress! Turns out the browser was caching the image, I just wasn't giving it time to do so (it just needed a second to load with an alert() or setInterval()). Now introducing what is probably the messiest code ever - I am using an infinite loop to create that pause.
The new method extends the old code above by binding a function (that adds each image's src to an array) to that image's successful load event. It then gets stuck in an infinite loop as it waits until all the images have loaded and therefore appeared in the array. This seems to work as a way to synchronously pre-load images - but a problem remains; the while() loop for some reason cycles infinitely even once all the images are loaded, unless I add an alert() to pause it for a moment.
The new code:
var html = '<img src="images/test.jpg" alt="test" />';
$('div.content').hide().html(html);
// define usr variables object
$.usrvar = {};
// array of loaded images' urls
$.usrvar.images = [];
// boolean for whether this content has images (and if we should check they are all loaded later)
$.usrvar.hasimages = false;
// foreach of any images inside the content
$('div.content img').each(function(){
// if we're here then this content has images..
$.usrvar.hasimages = true;
// set this image's src to a var
var src = $(this).attr('src');
// add this image to our images array once it has finished loading
$(this).load(function(){
$.usrvar.images.push(src);
});
// create a new image
var img = new Image();
// set our new image's src
img.src = src;
});
// avoid this code if we don't have images in the content
if ($.usrvar.hasimages != false) {
// no images are yet loaded
$.usrvar.imagesloaded = false;
// repeatedly cycle (while() loop) through all images in content (each() loop)
while ($.usrvar.imagesloaded != true) {
$('div.content img').each(function(){
// get this loop's image src
var src = $(this).attr('src');
// if this src is in our images array, it must have finished loading
if ($.usrvar.images.indexOf(src) != -1) {
// set imagesloaded to trueai
$.usrvar.imagesloaded = true;
} else {
// without the pause caused by this alert(), this loop becomes infinite?!
alert('pause');
// this image is not yet loaded, so set var to false to initiate another loop
// (ignores whether imagesloaded has been set to true by another image, because ALL
// need to be loaded
$.usrvar.imagesloaded = false;
}
});
}
}
$('div.content').slideDown('normal');
I made the following solution but it hasn't been tested, so you're warned ;)
// HTML (any formatting possible)
// no src for the images: it is provided in alt which is of the form url::actualAlt
var html = "<p><img alt='images/test.jpg::test' /><br />Some Text<br /><img alt='images/test2.jpg::test2' /></p>";
$(document).ready(function() {
// Reference to the content div (faster)
var divContent = $("div.content");
// Hide the div, put the HTML
divContent.hide().html(html);
// Webkit browsers sometimes do not parse immediately
// The setTimeout(function,1) gives them time to do so
setTimeout(function() {
// Get the images
var images = $("img",divContent);
// Find the number of images for synchronization purpose
var counter = images.length;
// Synchronizer
// will show the div when all images have been loaded
function imageLoaded() {
if (--counter<=0) $('div.content').slideDown('normal');
}
// Loading loop
// For each image in divContent
$.each(images,function() {
// Get the url & alt info from the alt attribute
var tmp = $(this).attr("alt").split("::");
// Set the alt attribute to its actual value
$(this).attr("alt",tmp[1]);
// Wire the onload & onerror handlers
this.onload = this.onerror = imageLoaded;
// Set the image src
this.src = tmp[0];
});
},1);
});
Create an interval/timeout and let it check your compterGenerated css-height, if it's autosized it'll begin from 0 and end to 100 (for example). But in Safari it loads the height before the image, so it'll propably not work in all browsers...
I was playing with this and I created a slightly different solution. Instead of pushing images onto an array when they are loaded, you push them all onto an array in the loop, then in the load event you remove them from the array and call a 'finished' function. It checks if the images array is empty, and if it is then it clears up and shows the content.
var html = '< animg src="images/test.jpg" alt="test" />'; // not allowed to post images...
$('div.content').hide().html(html);
// preload images
// define usr variables object
$.usrvar = {};
// array of loaded images' urls
$.usrvar.images = [];
// initially no images
$.usrvar.hasimages = false;
$('div.content img').each(function() {
// if we're here then this content has images..
$.usrvar.hasimages = true;
// set this image's src to a var
var src = this.src;
// add this image to our images array
$.usrvar.images.push(src);
// callback when image has finished loading
$(this).load(function(){
var index = $.usrvar.images.indexOf(src);
$.usrvar.images.splice(index,1);
finish_loading();
});
// create a new image
var img = new Image();
// set our new image's src
img.src = src;
});
if(!$.usrvar.hasimages) finish_loading();
function finish_loading() {
if($.usrvar.hasimages) {
if($.usrvar.images.length > 0) return;
}
$('div.content').slideDown('normal');
}
Edit: Looking at Julien's post, his method is better. My method works in a similar way but like the original solution keeps track of images by an array of srcs rather than just a count (which is more efficient).
Edit 2: well I thought it was a better solution, but it seems it doesnt work for me. Maybe something to do with the load event getting called too close to each other. Sometimes it will work but sometimes it will hang when loading images, and the image counter never reaches zero. I've gone back to the method in my post above.
Edit 3: It appears it was the setTimeout that was causing the problem.
This is what I use. As you can see by my points, I'm no pro, but I found this somewhere and it works great for me and seems much simpler than everything posted. Maybe I missed a requirement though. :)
var myImgs = ['images/nav/img1.png', 'images/nav/img2.png', 'images/nav/img3.png', 'images/nav/img4.png', 'images/expand.png', 'images/collapse.png'];
function preload(imgs) {
var img;
for (var i = 0, len = imgs.length; i < len; ++i) {
img = new Image();
img.src = imgs[i];
}
}
preload(myImgs);