Exactly when does an IFRAME onload event fire? - javascript

Does the IFRAME's onload event fire when the HTML has fully downloaded, or only when all dependent elements load as well? (css/js/img)

The latter: <body onload= fires only when all dependent elements (css/js/img) have been loaded as well.
If you want to run JavaScript code when the HTML has been loaded, do this at the end of your HTML:
<script>alert('HTML loaded.')</script></body></html>
Here is a relevant e-mail thread about the difference between load and ready (jQuery supports both).

The above answer (using onload event) is correct, however in certain cases this seems to misbehave. Especially when dynamically generating a print template for web-content.
I try to print certain contents of a page by creating a dynamic iframe and printing it. If it contains images i cant get it to fire when the images are loaded. It always fires too soon when the images are still loading resulting in a incomplete print:
function printElement(jqElement){
if (!$("#printframe").length){
$("body").append('<iframe id="printframe" name="printframe" style="height: 0px; width: 0px; position: absolute" />');
}
var printframe = $("#printframe")[0].contentWindow;
printframe.document.open();
printframe.document.write('<html><head></head><body onload="window.focus(); window.print()">');
printframe.document.write(jqElement[0].innerHTML);
printframe.document.write('</body></html>');
// printframe.document.body.onload = function(){
// printframe.focus();
// printframe.print();
// };
printframe.document.close();
// printframe.focus();
// printframe.print();
// printframe.document.body.onload = function()...
}
as you can see i tried out several methods to bind the onload handler... in any case it will fire too early. I know that because the browser print preview (google chrome) contains broken images. When I cancel the print and call that function again (images are now cached) the print preview is fine.
... fortunately i found a solution. not pretty but suitable. What it does that it scans the subtree for 'img' tags and checking the 'complete' state of those. if uncomplete it delays a recheck after 250ms.
function delayUntilImgComplete(element, func){
var images = element.find('img');
var complete = true;
$.each(images, function(index, image){
if (!image.complete) complete = false;
});
if (complete) func();
else setTimeout(function(){
delayUntilImgComplete(element, func);}
, 250);
}
function printElement(jqElement){
delayUntilImgComplete(jqElement, function(){
if (!$("#printframe").length){
$("body").append('<iframe id="printframe" name="printframe" style="height: 0px; width: 0px; position: absolute" />');
}
var printframe = $("#printframe")[0].contentWindow;
printframe.document.open();
printframe.document.write(jqElement[0].innerHTML);
printframe.document.close();
printframe.focus();
printframe.print();
});
}

Just when the html loads, not the dependent elements. (or so I think).
To fire when the rest of the page loads do jQuery(window).load(function(){ or window.onload not document onready.
You can also check to see if an image element is loaded and there... if image . load-- etc.

Related

Why is this java script not working?

In reference to this post: How to display loading image while actual image is downloading
I have the following code, but for some reason I cannot get the #loader_img to hide. I would also like to add a preloader because the large image is really heavy, but I want to keep it simple if possible since I am new to javascript...
<img id="loader_img" src="img/ajax-loader.gif" alt="Loading..." />
<div class="magnifier" style="height: 584px; width: 467px; margin: 20px;">
<div class="maglens">
<img id="imgload" src="img/largeimage.jpg" />
</div>
</div>
JS:
// show loading image
$("#loader_img").show();
$("#imgload").hide();
// main image loaded ?
$("#imgload").on('load', function(){
// hide/remove the loading image
$("#loader_img").hide();
});
Any help will be much appreciated! Thank you!
The image's load event is almost certainly firing before you hook the event. Since it's already fired when you hook the event, you never see it occur.
Also, you start out hiding the image (#imgload), but you never then show it.
To ensure that you get the event, you have to hook load before setting the image's src.
Alternately, you can use the image's complete property to know if it's already been loaded:
// show loading image
$("#loader_img").show();
$("#imgload").hide();
// main image loaded ?
var img = $("#imgload");
if (img[0].complete) {
imageDone();
} else {
img.on('load', imageDone);
}
function imageDone() {
// hide/remove the loading image
$("#loader_img").hide();
// And show the image!
img.show();
}
You also have to ensure that the code above runs after the elements have been created. The best way to do that is to put your script tag containing the code after the elements it refers to in the HTML (usually putting it just before the closing </body> tag works well). As a second-best solution, you can use jQuery's ready function. Either way, you'll still need to handle the possibility the load event has already fired.
Here's an example:
<div id="loader_img">Loading</div>
<div class="content">
<img id="imgload" src="http://i.stack.imgur.com/rTQCa.jpg?s=512&g=1" />
</div>
<script src="https://ajax.googleapis.com/ajax/libs/jquery/1.11.1/jquery.min.js"></script>
<script>
(function() { // Avoid creating globals
// show loading image
$("#loader_img").show();
$("#imgload").hide();
// main image loaded ?
var img = $("#imgload");
if (img[0].complete) {
console.log("Complete");
imageDone();
} else {
console.log("Wait for load");
img.on('load', imageDone);
}
function imageDone() {
console.log("Loaded");
// hide/remove the loading image
$("#loader_img").fadeOut();
// And show the image!
img.show();
}
})();
</script>
Hi you may use this method. jQuery.ready()I have tried on my computer and it's okay this way.
BTW, you forgot to let the "imgload" show again.
// show loading image
$("#loader_img").show();
$("#imgload").hide();
// main image loaded ?
$("#imgload").ready(function(){
// hide/remove the loading image
$("#loader_img").hide();
$("#imgload").show(); // show the loaded img again
});
I think that the script is executed before the DOM is loaded.
Take your script and put it between:
$(function () {
//Your code here
});
This will insure that the code will run after the DOM is loaded.

Jquery function not firing on initial load

I have a situation where I must wait for a Specific image to load, and then either swap out its src, or locate the next image and hide/show it.
What I need to happen is show a placeholder image (silhouette) until its main image is ready, and then hide the silhouette and show the main image. Very common stuff.
Problem is this jquery function does not fire on a new tab, or window... but if I hit f5 it works perfectly... but then again I open a new tab, and it wont fire until I hit f5.
CSS:
.staffImage1, .staffImage2, .staffImage3, .staffImage4, .staffImage5 { display: none; }
Jquery:
$('.staffImage1, .staffImage2,.staffImage3,.staffImage4, .staffImage5')
.load(function () {
$(this).next('.sillhouette').hide();
$(this).show();
console.log("function fired")
})
I get the log message only after refresh.
Something to be aware of is I am using the "First 14k" method to increase page speed, so maybe jquery just is not ready when the images are initially loaded the first time, but are cached and work after f5?
Each image must wait until its fully loaded, they are in a slider, so I need to show the first slides image as soon as its ready,I cannot wait until all 5 images are ready, as that would slow down the first slides image.
Any advice is appreciated, thank you
This structure:
$('.staffImage1, .staffImage2,.staffImage3,.staffImage4, .staffImage5').load(...)
does not work to notify you when all the images have been loaded. .load() only works on a single image at a time. And, if the images are cached, they may already have finished loading before your jQuery even runs so you would miss the load event entirely.
The simplest work-around is to use the window load event when all page resources have finished loading:
$(window).load(function() {
// all images are loaded here
});
It is also possible to monitor just those 5 images, but that is more work. I've written code to do this before so I'll see if I can find that prior code.
Here's a jQuery plug-in function that monitors just specific images. It will call its callback when all the images in the jQuery object are loaded:
// call the callback when all images have been loaded
// if all images are already loaded or there were no images in the jQuery
// object, then the callback will be called immediately
jQuery.fn.imgsLoaded = function(fn) {
var cntRemaining = 0;
function checkDone() {
if (cntRemaining === 0) {
fn();
}
}
function imgDone() {
--cntRemaining;
checkDone();
// remove event handlers to kill closure when done
$(this).off("load error abort", imgDone);
}
this.each(function() {
if (!this.tagName.toLowerCase() === "img" && !this.complete && this.src) {
++cntRemaining;
$(this).on("load error abort", imgDone);
}
});
checkDone();
return this;
}
You could use it like this:
$('.staffImage1, .staffImage2,.staffImage3,.staffImage4, .staffImage5').imgsLoaded(function () {
$(this).next('.sillhouette').hide();
$(this).show();
console.log("function fired")
});
Working demo: http://jsfiddle.net/jfriend00/zaoweyoo/
Write jquery code
'$(document).ready(function(){
//your code
});'

jQuery loaded html content - Check if images are loaded and rendered

I have tabs logic that load html templates inside a wrapper. That's works fine, but I included an animation that animate height of the tab wrapper when tab is switched.
The problem is the following: When a template contains <img src="/some-image.png"> the $('#tab-content').load('template-url', function() {...}) callback function sometimes is executed before the browser show the images. And my animation is not working correctly.
Code example (jsFiddle):
var currentHeight = $contentHolder.height();
$contentHolder.load(path, function() {
$contentHolder.stop();
function animateHeight() {
var loadedContentHeight = $contentHolder.css('height', 'auto').height();
$contentHolder.height(currentHeight);
$contentHolder.animate({
height: loadedContentHeight
}, 800, 'linear');
}
animateHeight();
});
I tried to set little timeout, but it's not working every time. If I set more that 300ms timeout, It feels like tabs are changed too slow.
I tried to execute the animation when $('img').load(function() {}) is fired, but with no luck.
This bug occurs most often when the web page is fully refreshed and each tab content loading for first time.
The image load event is kind of broken. To know when images are loaded you will have to observe the DOM for changes. Then on every change, you have to fetch all the new images 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.
One way to listen to DOM changes is the MutationObserver event. This is supported by all modern browsers and IE11.
A better supported solution (IE9 and up) 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).
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.
In your case you only want to fire your callback when all images are loaded, so I added a check if there's still images without the data-loaded attribute. If you remove that if-clause your callback would run after each image is loaded.
// Observe the DOM for changes
observeDOM(document.body, function(){
checkNewImages();
});
var checkNewImages = function() {
var images = $('img:not([data-loaded]').each(function() {
addImageLoadedEvent( this );
});
}
var addImageLoadedEvent = function(img) {
if (img.complete) {
onImageLoaded(img);
} else {
$(img).on('load', function() {
onImageLoaded(this);
});
}
}
// The callback that is fired once an element is loaded
var onImagesLoaded = function(img) {
$(img).attr('data-loaded', 'true');
if($('img:not([data-loaded])').length === 0) {
// YourCallbackHere();
}
}
DEMO: fire event on all images loaded
You can call your animateHeight function as each image in the loaded HTML is in turn loaded. You can expand this selection if you have other objects like videos.
// Call animateHeight as each image loads
var items = $('img', $contentHolder);
items.bind('load', function(){
animateHeight();
});
Updated demo: http://jsfiddle.net/jxxrhvvz/1/

div is filled dynamically with html after main page loads- how to determine it has been loaded

I inherited a project where a page is loaded, then code attached to that page fills in a div with dynamically generated html - it basically fills an existing div with a html string.
This string contains links to images, etc.
I want to tell when all the images, etc have loaded- I cannot seem to get any jQuery standard checks
to work - ie I have tried attaching $(window).load() after the dynamic stuff has been inserted.
I am wondering if I should write $(window).load() dynamically as well, or if there is any other
method- ie $("#thediv").load (doesn't seem to work. I cannot query all the new html for image tags, etc-
too much stuff is being put in.
The $(window).load() doesn't work for dynamic content as far as I know. You can use the .load event for each image separated. Here's an example:
var container = $("<div> ... Stuff ... </div>");
var images = container.find('img');
var imageIdx = 0;
images.load(function(){
imageIdx++;
if (imageIdx == images.length){
callback();
}
});
Where callback() is the function that runs after all images where loaded.
From my comment: window load applies to the initial page load only. Not dynamic loading of content within it. Attach load handlers to each loaded image element and count them.
This is the shortest version I could come up with for you:
// After HTML load finishes
var img = 0;
var imgCount = $("#thediv img").load(function(){
if (++img == imgCount){
// We are done loading all images!
}
}).length;
$(window).ready() only applies to the content within the HTML file and you can only use load to attach an onload event handler to a specific image (not a container), something like this might work for you.
window.ImageLoadHandled = false;
window.ImageLoadCount = 0;
function ImageLoadHandler() {
// guard against calling this function twice
if(window.ImageLoadHandled) return;
window.ImageLoadHandled = true;
// All images have loaded || timeout expired...
}
$("#myAjaxedDiv img").load( function() {
window.ImageLoadCount++;
if( window.ImageLoadCount == $("#myAjaxedDiv img").length ) {
// all images in #myAjaxedDiv have loaded
ImageLoadHandler();
}
});
// if images haven't loaded after 5 seconds, call the code
setTimeout( ImageLoadHandler, 5000 )
The only problem with this is that if an image fails to load for whatever reason, the code will never be hit, which is quite risky. To counteract this I'd recommend creating a setTimeout() method to call your code after a few seconds timeout in-case there is a problem loading images (client or server side) and I've also taken #TrueBlueAussie's correction into account in the edit.
Your alternative is to preload the images with your HTML page

How do I abort image <img> load requests without using window.stop()

I have a very long page that dynamically loads images as users scroll through.
However, if a user quickly scrolls away from a certain part of the page, I don't want the images to continue loading in that now out-of-view part of the page.
There are lots of other requests happening on the page simultaneously apart from image loading, so a blunt window.stop() firing on the scroll event is not acceptable.
I have tried removing & clearing the img src attributes for images that are no longer in view, however, since the request was already started, the image continues to load.
Remember that the image src was filled in as the user briefly scrolled past that part of the page. Once past though, I couldn't get that image from stop loading without using window.stop(). Clearing src didn't work. (Chrome & FF)
Similar posts I found that get close, but don't seem to solve this problem:
Stop loading of images with javascript (lazyload)?
Javascript: Cancel/Stop Image Requests
How to cancel an image from loading
What you are trying to do is the wrong approach, as mentioned by nrabinowitz. You can't just "cancel" the loading process of an image (setting the src attribute to an empty string is not a good idea). In fact, even if you could, doing so would only make things worst, as your server would continually send data that would get cancelled, increasing it's load factor and slow it down. Also, consider this:
if your user scroll frenetically up and down the page, he/she will expect some loading delays.
having a timeout delay (ex: 200 ms) before starting to load a portion of the page is pretty acceptable, and how many times will one stop and jump after 200 ms interval on your page? Even it it happens, it comes back to point 1
how big are your images? Even a slow server can serve about a few tens of 3Kb thunbnails per second. If your site has bigger images, consider using low and hi resolution images with some components like lightBox
Often, computer problems are simply design problems.
** EDIT **
Here's an idea :
your page should display DIV containers with the width and height of the expected image size (use CSS to style). Inside of each DIV, add an link. For example :
<div class="img-wrapper thumbnail">
Loading...
</div>
Add this Javascript (untested, the idea is self describing)
$(function() {
var imgStack;
var loadTimeout;
$(window).scroll(function() {
imgStack = null;
if (loadTimeout) clearTimeout(loadTimeout);
loadTimeout = setTimeout(function() {
// get all links visible in the view port
// should be an array or jQuery object
imgStack = ...
loadNextImage();
}, 200); // 200 ms delay
});
function loadNextImage() {
if (imgStack && imgStack.length) {
var nextLink = $(imgStack.pop()); // get next image element
$('<img />').attr('src', nextLink.attr('href'))
.appendTo(nextLink.parent())
.load(function() {
loadNextImage();
});
// remove link from container (so we don't precess it twice)
nextLink.remove();
}
};
});
Well, my idea:
1) initiate an AJAX request for the image, if it succeeds, the image goes to the browser cache, and once you set the 'src' attribute, the image is shown from the cache
2) you can abort the XHR
I wrote a tiny server with express emulating the huge image download (it actually just waits 20 seconds, then returns an image). Then I have this in my HTML:
<!DOCTYPE html>
<html>
<head>
<style>
img {
width: 469px;
height: 428px;
background-color: #CCC;
border: 1px solid #999;
}
</style>
</head>
<body>
<img data-src="./img" src="" />
<br />
<a id="cancel" href="javascript:void(0)">CANCEL</a>
<script src="http://ajax.googleapis.com/ajax/libs/jquery/1.6.2/jquery.min.js"></script>
<script>
$(function () {
var xhr, img = $('img'), src = img.data('src');
xhr = $.ajax(src, {
success: function (data) { img.attr('src', src) }
});
$('#cancel').click(function (){
xhr.abort();
})
});
</script>
</body>
</html>
You can load your images using ajax calls, and in case that the uses scrolls-out, you can abort the calls.
In jQuery pseudo-code it would be something like that (forgive me mistakes in syntax, it is just an example):
1) tag images that you want to load
$(".image").each( function(){
if ( is_in_visible_area(this) ) { // check [1] for example
$(this).addClass("load_me");
} else {
$(this).addClass("dont_load");
}
});
2) load images
ajax_requests = {};
$(".image.load_me").each( function(){
// load image
var a = $.ajax({
url: 'give_me_photos.php',
data: {img: photo_id},
success: function(html){
photo_by_id(photo_id), img.append(html);
}
});
ajax_requests[photo_id] = a;
});
3) cancel loading those out of the screen
for( id in ajax_requests ) {
if ( ! is_in_visible_area(id) ) {
ajax_requests[id].abort();
}
}
Of course, add also some checking if the image is already loaded (e.g. class "loaded")
[1]. Check if element is visible after scrolling
[2]. Abort Ajax requests using jQuery
BTW, another idea that might work:
1) create a new iframe
2) inside of the iframe have the script that starts loading the image, and once it's loaded, call the .parent's method
3) when in need, stop the iframe content loading using .stop on the iframe object
Use a stack to manage ajax requests (means you will have serial loading instead of parallel but it is worth it)
On scroll stop, wait for 300ms and then push all images inside view-area into stack
Every time a user scrolls check if a stack is running. (fyi - you can stop all requests to a particular url instead of killing all ajax calls. also you can use regex so it should not stop any other requests on the page)
If an existing stack is running - pop all the images that are in it except for the top most one.
On all ajax calls - bind beforeSend() event to remove that particular image from the stack
It is late right now, but we have done something very similar at work - if you need the detailed code let me know.
Cheers!
Maybe you could serve the image through a php script which would check a field in the the db (or better yet a memcached) that would indicate stop loading. the script would portion up the image into chunks and pause in between each chunk and check if the stop flag for the particular request is. If it is set you send the header with A 204 no content which as soon as the browser gets it will stop receiving.
This may be a bit over kill though.
The solution could be a webworker. a webworker can be terminated and with him the connection.
But there is a small problem that the webworker uses the limited connections of the browser so the application will be blocked.
Right now I'm working on a solution with serviceWorkers - they don't have a connection limit (I hope so)

Categories