Check if children elements (images) are loaded before executing? - javascript

I have a div which contains a number of images. I would like to check if all the images in this div are loaded before executing some code. I can't work it off the entire document as there are other things on the page which may take much longer to load.
How can I do this? jquery is available for use.

You should sue the load event
$('img').load(function(){
//here do what you need to do when the img is loaded
});
there are some caveats
Caveats of the load event when used with images
A common challenge developers attempt to solve using the .load()
shortcut is to execute a function when an image (or collection of
images) have completely loaded. There are several known caveats with
this that should be noted. These are:
It doesn't work consistently nor reliably cross-browser
It doesn't fire correctly in WebKit if the image src is set to the same src as before
It doesn't correctly bubble up the DOM tree
Can cease to fire for images that already live in the browser's cache

You can do sth like this:
var files = ['a.jpg','b.png']; //defines all assets needed
$.each(files,function(){
var tmp = new Image();
tmp.src = this; //creates a new dummy object
tmp.on('load',function(){
var i = files.indexOf(this);
files.splice(i,1); //when dummy object has loaded it gets removed from array
if (!files.length){ //when array is empty we're all set
alert('Preloading done!');
}
});
});

Related

jQuery load event - discrepancies in usage

A lot of the time we load an image via jQuery in the background before appending it to the DOM like so
var image = $('<img src="https://placeholdit.imgix.net/~text?txtsize=33&txt=350%C3%97150&w=350&h=150" />');
image.load(function(){
//the image is now loaded and can be appended
});
Although stated in the docs that there are caveats to this method (that ultimately it is not 100% reliable), it is a good method for what we need.
Taking this principle, I want to load an iframe and wait for it to be loaded before proceeding
//method does not fire
var iframe = $('<iframe src="http://example.com"></iframe>');
iframe.load(function(){
//the iframe is now loaded and can be appended
});
However, it appears to be so that the iframe needs to be in the DOM before that load event is called, in contrast to the loading of the image:
//method now fires
var iframe = $('<iframe src="http://example.com"></iframe>');
$("body").append(iframe);
iframe.load(function(){
//the iframe is now loaded and can be appended
});
What is the reason for this? I cannot seem to find it documented anywhere. I know in practice it'd be easy enough to set the style to display none then manipulate it once it's loaded, but I'm more interested in the why as opposed to the how. Thanks!

jquery: exclude external resources from $(window).load()

I need to execute some scripts when all the resources on my domain and subdomain are loaded, so I did this:
$(window).load(function(){
// al my functions here...
}
The problem is that there are some external resources (not on my domain and subdomain) that sometimes take longer to load. Is there a way to exclude external resources from the load event?
EDIT:
I was hoping to do something like:
$(window).not(".idontcare").load(function()
but it's not working
I guess your external resources rely on a src attribute.
If so, in your page source code you could set the src attribute of the resources you don't want to wait for, not as src but as external_src.
Then you could easily do:
$(document).ready(function(){
$(window).load(function(){
// all your functions here...
});
$('[external_src]').each(function() {
var external_src = $(this).attr("external_src");
$(this).attr("src", external_src); // now it starts to load
$(this).removeAttr("external_src"); // keep your DOM clean
//Or just one line:
//$(this).attr("src", $(this).attr("external_src")).removeAttr("external_src");
});
});
This way the external resources should start loading as soon as just the DOM is ready, without waiting for the full window load.
I have almost same case. But in my case, I want to exclude all iframes that load content from another site (e.g. youtube, vimeo etc). Found a work around, so the scenario is hide 'src' attribute from all iframes when DOM is ready and put it back when window is finish load all another content.
(function($){
//DOM is ready
$(document).ready(function(){
var frame = $('iframe'),
frameSrc = new Array();
if( frame.length ){
$.each( frame, function(i, f){
frameSrc[i] = $(f).attr('src');
//remove the src attribute so window will ignore these iframes
$(f).attr('src', '');
});
//window finish load
$(window).on('load',function(){
$.each( frame, function(a, x){
//put the src attribute value back
$(x).attr('src', frameSrc[a]);
});
});
}
});
})(jQuery);
You can mark all elements in your site that load external resources by adding a special class, and change the iframe with $('.special_class') or something like that. I dont know if this is the best way but at least it works great in my side :D
Unfortunately, the window.onload event is very strict. As you might know it will fire when all und every resource was transfered and loaded, images, iframes, everything. So the quick answer to your question is no, there is no easy-to-use way to tell that event to ignore external resources, it makes no difference there.
You would need to handle that yourself, which could be a tricky thing according to how those resources are included and located. You might even need to manipulate the source code before it gets delivered to accomplish that.
As far as I know, there is an async - tag for script tags. You can your includes to:
<script src="script_path" async="true"></script>
This will not include them to the event.
maybe
$(document).ready(...)
instead of $(window).load() will help?
The document ready event executes already when the HTML-Document is loaded and the DOM is ready, even if all the graphics haven’t loaded yet.

load specific image before anything else

I'm a creating a loading screen for website I am making. The website loads many images, scripts, etc. The HTML and CSS part is great, but I need a way to guarantee that the "loading..." image will be loaded before anything else.
I'm using jQuery, and everything is initiated within $(function () { ... });. I imagine that the code for this would need to be called before/outside that block, and the code to remove the loading screen will be called at the very end of that block. Currently, the loading image is set as a DIV background, which is the way I prefer it. However, if it's completely necessary, I will settle for an IMG tag.
Update: (solution)
I was able to answer my own question by using a combination of Robin and Vlad's responses. Both were very good, and excellent answers, however the problem is that they were aimed to load an image before another image, rather than load an image before anything else. (CSS, JS, etc...)
Here's the dirty version of what I came up with:
var files = [new Image(), document.createElement('link'), document.createElement('script')];
files[0].setAttribute('src', 'images/loading.gif');
files[1].setAttribute('rel', 'stylesheet');
files[1].setAttribute('type', 'text/css');
files[1].setAttribute('href', 'test.css');
files[2].setAttribute('type', 'text/javascript');
files[2].setAttribute('src', 'js/jquery-1.5.1.min.js');
window.onload = function (e) {
document.getElementsByTagName('head')[0].appendChild(files[1]);
document.getElementsByTagName('head')[0].appendChild(files[2]);
}
Taking a look at the load sequence on the network tab of Chrome's developer console shows that 'loading.gif' is loaded first, then 4 dummy images, then 'test.css', and then 'jquery.1.5.1.min.js'. The CSS and JS files don't begin to load, until they've been inserted into the head tag. This is exactly what I want.
I'm predicting that I may begin to have some problems, however, when I begin to load a list of files. Chrome reports that sometimes the JS file is loaded first, but the majority of the time the CSS file is loaded first. This isn't a problem, except when I begin to add files to load, I will need to ensure that jQuery is loaded before a script file that uses jQuery.
If anyone has a solution for this, or a way to detect when the CSS/JS files are finished loading, using this method, then please comment. Though, I'm not sure that it's going to be a problem yet. I may need to ask a new question in the future about this, if I start to run into problems.
Thank you to every who has helped with this issue.
Update: (glitch fix)
I ended up running into a lot of problem with this method, because the script files were being loaded asynchronously. If I would clear the browser cache, and then load the page, it would finish loading my jquery dependent files first. Then if I refreshed the page, it would work, because jquery was loaded from cache. I solved this by setting up an array of files to load, then putting the load script into a function. Then I would step through each array item using this code:
element.onload = function() {
++i; _step();
}
element.onreadystatechange = function() {
if (("loaded" === element.readyState || "complete" === element.readyState)) { ++i; _step(); }
}
You can reuse resource prealoding browser support.
I'm not sure it works across all browsers but in my case this approach helps me to load images first. Also it allows to define concrete images so UI specific could be skipped
First define in header what resource you want to preload and define resource priority
<link rel="preload" href="link-to-image" as="image">
or
<link rel="preload" href="link-to-image">
Second line allow to increase loading priority across all object types (scripts / images / styles). First line - only through images.
Then define in body link to image as usual:
<img src="link-to-image" alt="">
Here is my working example
https://jsfiddle.net/vadimb/05scfL58/
As long as the "loading..." image is positioned before any other html elements, it should load first. This of course depends on the size of the image. You could put the loading div right after the tag and position it using 'position:absolute'.
Regarding the code to remove the loading screen, one method is to do the following.
Put all the images, scripts that need to be loaded in a hidden div (display: none)
Set up a variable that will hold the total of the images / scripts to be loaded
Set up a counter variable
Attach to each image / script the "onload" event
Everytime the "onload" event is triggered it will call a function that will increment the counter variable and check if the value of the counter equals the value of the total variable
If all resources have been loaded, fire a custom event that will show the div with the images, and hide the div with the loading screen.
The code below isn't tested so it might not work. Hope it helps
var totalImages = 0;
var loadCounter = 0;
function incrementLoadCounter() {
loadCounter++;
if(loadCounter === totalImages) {
$(document).trigger('everythingLoaded');
}
}
function hideLoadingScreen() {
$('#loadingScreen').hide();
$('#divWithImages').show();
}
$(document).ready(function(e) {
$('#loadingScreen').bind('everythingLoaded', function(e) {
hideLoadingScreen();
});
var imagesToLoad = $('img.toLoad');
totalImages = imagesToLoad.length;
$.each(imagesToLoad, function(i, item) {
$(item).load(function(e) {
incrementLoadCounter();
})
});
})
I'm not sure if it's possible to enforce.
If it is, try adding this in the head-tag:
<script type="text/javascript">
if(document.images)
(new Image()).src="http://www.image.com/example.png";
</script>
In theory that may load and cache that image before anything else.
I think if you place the IMG tag at the top of your html body it will be loaded first. If you do not want to move your div just use a copy of the image tag. Once the images is loaded it will be shown in every image tag which shows the same picture.
Or you could use spin.js as loading image. It display this "loading cycle image" via javascript.
Check it out under:
http://fgnass.github.com/spin.js/

Explicitly setting load order

I have a slight problem.
I need to show some safety information in a JS drawer that the page loads with open. The images creating the drawer are kind of hefty and as such the safety text in the drawer render prior to the background, creating a really ugly loading experiance. Is there a easy way I can say
DO NOT LOAD safetyText UNTIL safetyBG is loaded ?
We're not using any libraries (i.e. jQuery) so a JS solution would have to work as a script by itself.
If I understand you correctly, you only want to display safetyText once safetyBG has fully loaded. To achieve that, hide safetyText, then check on document.onload if safetyBG has loaded. If so, show text, if not, attach function to show text to safetyBG.onload:
function showSafetyText() {
//show text
}
window.onload = function() {
var safetyBG = document.getElementById("safetyBG"); // tweak as necessary
//have to check to see if img loaded, if you would simply assign showSafetyText
//to img.onload, it would never run if the img was fully loaded already
if (!safetyBG.complete) {
safetyBG.onload = showSafetyText;
} else {
showSafetyText();
}
}
You mentioned images (rather than a single image) in your post. If that's the case you'll want to write a function that loops through the images to check to see if they've all loaded (at which time you can load the text); then attach this function to each of the images' onload events (unless all images are loaded already in which case you can simply show the text).

JavaScript - override or prevent execution

I'm working on a client project and I have to include their header and footer, which includes some core JavaScript files. I have a couple of PNGs on the page, but their core JS file is poorly coded and doesn't check for IE 7 before attempting to replace IMG tags that contain .png files with DIVS that use the AlphaImageLoader filter. The result is that in IE 7, all my .png images are replaced with DIV tags that have a default display: block, causing a linebreak after every single png image in my pages.
What I'd like to do is override their function with a better one or somehow prevent theirs from executing, but I cannot modify the JS file itself, which both defines the function and attaches it to the window onload event. I've tried redefining the function under the same name in several places (header, just before the /body tag, in $(document).ready, etc...) but the original function always seems to execute, presumably because the original function code is what is stored with the event handler, and not merely a pointer to the function.
Any way I can fix? Is there a way to selectively remove onload event handlers?
If that's the only thing running at load, I think you could do
window.onload = null;
If there are other things running, I guess you'd have to reattach them. It's a little fragile, I suppose.
In IE7 you can use the detachEvent method:-
window.detachEvent("load", fn)
where fn is the function that was attached, however since there is jquery in this mix it may be a tall order getting hold of the actual function that was attached. Most likely the actual function attached will be anonymous.
A large IFRAME between header & footer should do the trick.
Well, depending on how it was bound, you might be able to get away with something like:
window.onload = function(){
var alert=function(a){
console.log(a);
}
window.onload();
}
Obviously, you'd want to redefine something other than alert, but that might work.
maybe if that's all it does, you can write a function to reverse it, look for all png images and strip away the div, and if you want to skip certain images you can implant an attribute to those you want to treat differently
another way is to trick the function by not having the png part of the image file name, and on load, append the .png (after their onload)
or maybe you can replace your png images with another tag, and replace onload
by the way, you can know exactly whats inside the onload, if you just alert window.onload, if there is nothing but that functionality, set window.onload = null;
Have you tried using $(window).unbind("load")?
Do you know the name of the function that replaces the PNG images? If so you might be able to override the existing function by doing something like this:
// Assuming PNG function is called pngSwap
function pngSwap() {
alert('png swap');
}
$(document).ready(function() {
if (window.pngSwap && window.pngSwap.constructor === Function) {
var oldFunc = window.pngSwap;
window.pngSwap = function() {
alert('new png swap');
}
}
pngSwap();
});

Categories