Execute code after all images are loaded - javascript

I want to do some interface fixes after all images are loaded (need the heights of the elements that hold images and use them to change the heights of other elements) I attach load event to all images but my load function is executed only once. I've try to use only jQuery:
$(function() {
var $img = $('img');
var length = $img.length;
var count = 0;
function load() {
console.log(++count + ' == ' + length);
if (count == length) {
// all images loaded
}
}
$img.load(load).error(load);
});
I also try to use onload and onerror events:
$img.each(function() {
this.onload = load;
this.onerror = load;
});
but when page is loaded I've got just one log:
1 == 33
(I'm testing in Chromium on Xubuntu with Dev Tools and cache disabled)
What I've doing wrong here? How to execute code after all images are loaded?

Sounds like you should be handling on the window's load event:
$( window ).load(function() {
// Glorious code!!
}
From the docs: "Run a function when the page is fully loaded including graphics."
http://api.jquery.com/load-event/

Execute the function when the page has finished loading
$(window).load
That way all elements are in place and ready to be 'measured'

Related

how to know when an iframe has finished loading the DOM, but not yet all images?

My web page has an iframe, and I change its src when the user clicks on a showNewPage button. I need to know when the browser has finished loading the DOM of the iframe, but without waiting for all the images to be downloaded.
var myIFrame = document.getElementById("myIframe")
var count = 0;
funcion showNewPage() {
myIFrame.src = "http://example.com/page_" + count;
count++;
}
This code calls doSomething() when the iframe has finished loading the DOM and all images:
myIFrame.addEventListener("load", function(event) { doSomething(); });
How to ask myIFrame to call doSomething() when the iframe has finished loading the DOM, but not yet all the images?
ps: There is an event DOMContentLoaded instead of load which achieves this; but this event is not available for an iframe. It's available only for a document or a window. Doing as follows does not work neither, because myIFrame.contentWindow returns null at the very beginning:
myIFrame.contentWindow.addEventListener("DOMContentLoaded", function(event) { doSomething(); });
ps: this other question does not answer my question, as it relies on onload event, which waits until all images are downloaded: How to detect when an iframe has already been loaded
As you found out, trying to get its .contentWindow before the iframe has been initialized will return null.
One way around this is to
initialize your frame with an empty document (about:blank),
get a reference to your iframe's contentWindow, this will always be the same object, however events we attach on it will get removed at every new navigation...
add an unload event listener (since it's the closest to the navigation)
wait just a frame so our contentWindow start the navigation
add your DOMContentLoaded and our unload event listeners so we can reiterate at next navigation
frame.onload = e => {
const win = frame.contentWindow;
frame.onload = null;
win.addEventListener( 'unload', attachEvents );
YOUR_CALLBACK(); // make it fire even at beginning?
function attachEvents() {
setTimeout( () => {
win.addEventListener( 'DOMContentLoaded', YOUR_CALLBACK );
win.addEventListener( 'unload', attachEvents ); // do it again at next navigation
}, 0 );
};
};
frame.src = "about:blank";
As a fiddle since StackSnippets over-protected iframes don't allow us to access inner frames' content...

Perform image analysis only after images are already loaded

I am looking for a way to scale images of a web page for mobile devices. My approach is to store the dimensions of each image using JavaScript, and if the screen of the user is smaller than a certain value, all images will be resized using JavaScript. My problem is that the following function does not detect if the images are already loaded, so the result would be 0 for not loaded images. My question is, how can I implement a check, so that the function will compute the image size only after the image was completely loaded? I am not using jQuery.
function storeImageSizes() {
isizes = [];
imgs = document.getElementById('content').getElementsByTagName('img');
for (var i = 0; i < imgs.length; i++) {
isizes[i] = [
window.getComputedStyle(imgs[i]).getPropertyValue('width').replace('px', '') * 1,
window.getComputedStyle(imgs[i]).getPropertyValue('height').replace('px', '') * 1
];
}
}
Add a listener to be called when all DOM elements load. ie:
document.addEventListener("load", (function(){
isizes = [];
imgs = document.getElementById('content').getElementsByTagName('img');
for (var i = 0; i < imgs.length; i++) {
isizes[i] = [
window.getComputedStyle(imgs[i]).getPropertyValue('width').replace('px', '') * 1,
window.getComputedStyle(imgs[i]).getPropertyValue('height').replace('px', '') * 1
];
}
})
Did you try image.onload?
Also, check this answer out. It highlights the use of image.onload and also avoids browser cache issues.
You can use the following solution to perform image analysis after the images are already loaded:
document.querySelector('#image').addEventListener('load', storeImageSizes);
Calling storeImageSizes() in window.load function should fix the problem
$( window ).on( "load", function() { ... })
It basically is an event which is triggered when all the images and the complete page is loaded. Since you want the function to run when all the images are loaded you should use this event.
Note the difference between document.ready and window.load.
document.ready runs when the DOM is ready where as window.load runs once the complete page is loaded i.e., images/iframes etc.
Take reference from here Simple example using Jquery

How to iterate through set of elements and check each if loaded before go to the next?

I guess I need some help with this. I have the following code that checks if an iframe (containing a google doc viewer document) on my page is loaded and if not reloads it until it finally has happened to be loaded.
function reloadIFrame() {
// force iframe to reload
document.getElementsByClassName("preview-frame").src=document.getElementsByClassName("preview-frame").src;
}
timerId = setInterval("reloadIFrame();", 2000);
jQuery( document ).ready(function() {
jQuery('.preview-frame').on('load', function() {
clearInterval(timerId);
console.log("Finally Loaded");
});
});
In case someone is interested why: this is indeed needed because the Google Doc Viewer tends to not fully load the content (and then interrupts process) once in while and so you have only an 80% chance that content is actually shown instead of blank space.
The above code works fine but now I have the situation to have several iframes on my page.
What I want to achieve is kind of a loop that for each element starts a new interval until its content is loaded and then goes to the next one, until all iframes are reliably loaded and content is really displayed.
Someone with a helping hand how to achieve this? Thanks so much in advance!
You could make a new function and give the element you need to load as a parameter. Also call the callback after the element was loaded:
function loadIframe(iframeElement, callback) {
function reloadIFrame() {
// force iframe to reload
iframeElement.src = iframeElement.src;
}
timerId = setInterval("reloadIFrame();", 2000);
jQuery( document ).ready(function() {
jQuery(iframeElement).on('load', function() {
clearInterval(timerId);
callback(iframeElement);
});
});
}
// Here you can call the function
var iframes = document.getElementsByClassName("preview-frame");
for (var i = 0, len = iframes.length; i < len; i++) {
loadIframe(iframes[i], function(element){
console.log(element, 'finally loaded');
});
}

Perform animation on a page after page has loaded

I am doing maintenance work for a website. The logo on the home page is supposed to bounce in from left after page has loaded but the animation begins even when the page is still loading.
The code is
$(document).ready(function(){
$('#logo-large').addClass('animated bounceInLeft');
});
The site is using animate.css library
The ready method do not wait for resources to load.
While JavaScript provides the load event for executing code when a page is rendered, this event does not get triggered until all assets such as images have been completely received. In most cases, the script can be run as soon as the DOM hierarchy has been fully constructed. The handler passed to .ready() is guaranteed to be executed after the DOM is ready, so this is usually the best place to attach all other event handlers and run other jQuery code. When using scripts that rely on the value of CSS style properties, it's important to reference external stylesheets or embed style elements before referencing the scripts.
Reference: https://api.jquery.com/ready/
Use window.load method:
The load event is sent to an element when it and all sub-elements have been completely loaded. This event can be sent to any element associated with a URL: images, scripts, frames, iframes, and the window object.
$(window).on('load', function() {
$('#logo-large').addClass('animated bounceInLeft');
});
Reference: https://api.jquery.com/load-event/
The problem here is that you say "page loaded" but you haven't defined what that means. The animation is, indeed, playing after the DOM has loaded. That's what the $(document).ready method insures. However, any images or asynchronous calls can still trigger after the DOM is ready. So... the REAL question is, do you want to wait til after the images have loaded AND do you have any asynchronous calls that need to be accounted for.
I just wrote this so I'm not 100% sure if it doesn't have any bugs, but this should work for both cases.
jQuery.prototype.pageComplete = function(promises, callback){
if(!callback){
callback = promises;
promises = [];
}
var images = jQuery.Deferred();
var DOMReady = jQuery.Deferred();
var count = this.length;
promises.push(images);
promises.push(DOMReady);
jQuery(document).ready(function(){
DOMReady.resolve();
});
function counter(){
if(--count == 0) images.resolve();
}
this.each(function(image){
var img = new Image();
img.onload = counter;
img.src = image.src;
});
jQuery.when.apply(jQuery, promises).then(callback);
};
You use it like so:
// for just images
$('img').pageComplete(function(){
// code to transition image here
});
// for images and ajax
$('img').pageComplete([
ajax1, // these are all promises created by jQuery.ajax
ajax2,
ajax3
],
function(){
// code to transition image here
});
Try this one, solution should work without jquery
window.onload = function() {
document.getElementById('logo-large').classList.add('animated', 'bounceInLeft');
};
Use The Window Load Function
This will wait until the whole page has loaded before running the animation
jQuery(window).load(function() {
$('#logo-large').addClass('animated bounceInLeft');
});)
<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js"></script>

Fire event when images in generated content are loaded

I've got a problem with some Javascript-generated content :
I use the onload() event of my html page to load HTML code from a server and inject it in the page. Since it already is html I use the innerHtml property of the nodes I want to fill with content.
Once I've injected the HTML I call a handmade adjustHeights() function that normalizes the height of the elements I created this way to make them all match the height of the tallest element.
All of this works perfectly unless the code inside innerHtml contains some sort of image or other media that takes time to load (particularly videos) because adjustHeights() is called between the injection of the code and the end of the loading time of the image/video/etc.
Is there any way to wait for every element to be loaded before calling adjustHeights() ? I've already tried the document.onreadystatechange property but the state is already on 'completed' when I start to inject code.
If it's possible I would rather not use time-based calls on adjustHeights().
To make it clearer here's an example :
var mylist = document.getElementById('mycontent');
var li;
for (var i = 0; i < res.length; i++)
{
li = document.create('li');
li.innerHTML=res[i];
mylist.appendChild(li);
}
adjustHeights();
To do this without adding an inline onload attribute to all the images/videos/etc you will have to observe the DOM for changes. Then on every change, you have to fetch all the new media and add the onload event to them from the callback. To prevent checking each element every time, once they've been loaded you could mark them as such by adding a data-loaded="true" property for instance.
A cross-browser solution to observe DOM changes can be found in this answer: Detect changes in the DOM. I will not repeat it here (but it's included in the demo below).
Note: I use images as an example, but this should also work for videos and other media.
On every DOM change first you check for images without the data-loaded attribute that are already loaded anyway (this could happen when an image was still in the browser's cache) by checking element.complete. If so, fire the callback function and add the attribute to it.
If .complete is not the case, add an onload event to them that also fires the callback once it is loaded.
// Observe the DOM for changes
observeDOM(document.body, function(){
checkNewMedia();
});
// Loop through all new media, add the event
var checkNewMedia = function() {
// extend this by using document.querySelectorAll("img:not([data-loaded), video:not([data-loaded])") etc.
var media = document.querySelectorAll('img:not([data-loaded]');
for(var i = 0; i < media.length; i++) {
addMediaLoadedEvent(media[i]);
}
}
// Fire the callback if complete, otherwise bind to onload
var addMediaLoadedEvent = function(element) {
if (element.complete) {
onMediaLoaded(element);
} else {
element.addEventListener('load', function(event) {
onMediaLoaded(event.target);
});
}
}
// The callback that is fired once an element is loaded
var onMediaLoaded = function(element) {
element.setAttribute('data-loaded', 'true');
adjustHeights(); // <-- your function
}
DEMO: fire event on each image load
If you only want to fire the event once all images are loaded, you could add an extra check that counts how many images are still not loaded:
// The callback that is fired once an image is loaded
var onMediaLoaded = function(element) {
element.setAttribute('data-loaded', 'true');
// only fire when there are no media elements without the 'data-loaded' attribute left
// again, can be extended to use video, etc.
if(document.querySelectorAll('img:not([data-loaded])').length === 0) {
adjustHeights(); // <-- your function
}
}
DEMO: fire event on all images loaded
For image and other sort of media, you should use "onload" event so that you can call adjust height after that.
Example:
<img src="someimage.png" onload="loadImage()" >
<script>
function loadImage() {
// code to adjust heights
}
</script>
Here is the standard version:
var img = document.querySelector('img')
function loaded() {
alert('loaded');
// do something to adjust height
}
if (img.complete) {
loaded()
} else {
img.addEventListener('load', loaded)
img.addEventListener('error', function() {
alert('error')
})
}

Categories

Resources