IE has attribute readyState in document object, that indicates current state, e.g. "loading", "complete" etc.
Is there any way to find current loading state of document in Mozilla-based browsers?
I'm aware of DOMContentLoaded event, but it wont fit my situation, as my code can be executed after this event was fired.
Added: no, I can't use any framework, and don't confuse with .readyState attribute of XHR object.
And it's a bookmarklet, so it can be inserted in at any loading stage.
Added later: Anyway, it looks like it's not a big issue for me. Because this attribute will be added in FF3.6, and it does not break things badly in Firefox, when you manipulate on unfinished DOM (unlike IE).
No, it's not possible. Sorry. But here's what you can do. If you can't test for stuff you want to be there before acting:
window.setTimeout(function () {
// do your stuff here
}, 0);
(This will definitely do it after the page renders, but it might be after onload, not after DOMContentLoaded.)
If you do know how to test for what you're looking for:
(function () {
if (/* test if what you're looking for is there */) {
// do your stuff
} else {
window.setTimeout(arguments.callee, 0);
}
})();
This will do it immediately, unless whatever you're looking for is not there, in which case it will wait until after the onload event.
Edit:
Check out this solution.
What it does is, in the edge cases, checks if the last element of document.getElementsByTagName("*") is undefined or not. And that seems to work for him, even in Opera.
Can be executed? Just be notified of the DOM event and store its state. I don't see what your root problem is. Surely you could rip out the guts of this method and adapt it to your situation.
jQuery's way of doing it:
// Mozilla, Opera and webkit nightlies currently support this event
if ( document.addEventListener ) {
// Use the handy event callback
document.addEventListener( "DOMContentLoaded", function(){
//do stuff
}, false );
// If IE event model is used
} else if ( document.attachEvent ) {
// ensure firing before onload,
// maybe late but safe also for iframes
document.attachEvent("onreadystatechange", function(){
if ( document.readyState === "complete" ) {
document.detachEvent( "onreadystatechange", arguments.callee );
jQuery.ready();
}
});
// If IE and not an iframe
// continually check to see if the document is ready
if ( document.documentElement.doScroll && window == window.top ) (function(){
if ( jQuery.isReady ) return;
try {
// If IE is used, use the trick by Diego Perini
// http://javascript.nwbox.com/IEContentLoaded/
document.documentElement.doScroll("left");
} catch( error ) {
setTimeout( arguments.callee, 0 );
return;
}
// and execute any waiting functions
jQuery.ready();
})();
}
// A fallback to window.onload, that will always work
jQuery.event.add( window, "load", jQuery.ready );
Related
I know similar questions have been asked here before, but I can't find any that asks or answers this specific question.
I want an as simple as possible pure JavaScript ready function that runs when the page has fully loaded, similar to the jQuery $(document).ready() function.
I keep finding this example:
if (document.readyState === "complete" || (document.readyState !== "loading" && !document.documentElement.doScroll)) {
// Document already fully loaded
ready();
} else {
// Add event listener for DOMContentLoaded (fires when document is fully loaded)
document.addEventListener("DOMContentLoaded", ready);
}
function ready() {
// Handler here
}
but the websites giving this example always talk about support for older versions of IE, and I don't need that. I want to support only modern browsers (Chromium Edge, Chrome, Firefox, Opera and Safari), and hope to find a simpler solution, particularly regarding the part document.readyState !== "loading" && !document.documentElement.doScroll. I can't seem to find much information about document.documentElement.doScroll, at least not from reliable sources like MDN, so I don't know exactly what it does, or if removing this could cause the ready function to break in certain edge cases.
I guess what I'm asking is this:
Is it safe to remove document.readyState !== "loading" && !document.documentElement.doScroll from the example code, and are there even better ways to do this now when you only care about the current major browsers (listed above)?
It looks like doScroll is an IE thing. The readyState check is useful though, since the DOMContentLoaded event won't fire if it's already occurred. So, if you don't need IE support, I'd say you are fine removing the doScroll check, leaving you with:
if (document.readyState === "complete") {
// Document already fully loaded
ready();
} else {
// Add event listener for DOMContentLoaded (fires when document is fully loaded)
document.addEventListener("DOMContentLoaded", ready);
}
function ready() {
// Handler here
}
I'm working on an issue for the 2048 game which is a webapp that's been ported to Android:
https://github.com/uberspot/2048-android/issues/15
The JavaScript seems to work everywhere except for a button that toggles a style change in the app. The JavaScript works in a browser, just not in the app. I think it comes down to some code in nightmode.js which begins:
window.onload = function() {
var a = document.getElementById("night");
a.onclick = function() {<<code that toggles day and night colors>>}
Does anyone have a solution to why this JavaScript isn't getting run?
Edit: When on Desktop Chrome and the screen is resized all the way down, the button continues to work. But switching the device mode in Chrome reveals that the thing never works for mobile devices. Since this behavior happens even without the WebView, it looks like just a javascript problem now.
The onload event is fired when everything is loaded. This can take some time.
Plus, window.onload might get overwritten later on...
You can try this instead:
var ready = function ( fn ) {
// Sanity check
if ( typeof fn !== 'function' ) return;
// If document is already loaded, run method
if ( document.readyState === 'complete' ) {
return fn();
}
// Otherwise, wait until document is loaded
// The document has finished loading and the document has been parsed but sub-resources such as images, stylesheets and frames are still loading. The state indicates that the DOMContentLoaded event has been fired.
document.addEventListener( 'interactive', fn, false );
// Alternative: The document and all sub-resources have finished loading. The state indicates that the load event has been fired.
// document.addEventListener( 'complete', fn, false );
};
// Example
ready(function() {
// Do night-mode stuff...
});
see: http://gomakethings.com/a-native-javascript-equivalent-of-jquerys-ready-method/
I'm putting this up as a way to save people time.
I'm using jQuery 1.11.3, and MVC with ScriptBundle
On large pages I started getting errors calling addEventListener in ready.promise
Funnily enough, given u = document;
u.addEventListener = undefined
but looking at Methods under u shows addEventListener
same where u = window;
Looking at the jQuery source, it was obviously
if ( document.readyState === "complete" ) {
// Handle it asynchronously to allow scripts the opportunity to delay ready
setTimeout( jQuery.ready );
// Standards-based browsers support DOMContentLoaded
} else if ( document.addEventListener ) {
// Use the handy event callback
document.addEventListener( "DOMContentLoaded", completed, false );
// A fallback to window.onload, that will always work
window.addEventListener( "load", completed, false );
// If IE event model is used
}
and the jQuery-1.11.3.min.js was:
else if(y.addEventListener)y.addEventListener("DOMContentLoaded",J,!1),a.addEventListener("load",J,!1);else
So I was going mad trying to figure out the problem.
Then in the js output in the IE debugger I noticed:
else y.addEventListener("DOMContentLoaded",J,!1),a.addEventListener("load",J,!1);else
The check for addEventListener was not there.
I changed the Script Bundle from jquery-{version}.js to jquery.1.11.3.js and everything worked (and the if statement was present).
I changed it back again, and it continued to work, so obviously there is something compilation dependent going on.
I tracked this down eventually to the MVC minification process either caching or stripping some stuff out of the jQuery scripts. But ONLY if the script were the .min version in the first place.
I need to attach a submit listener to every form in an iframe but I can't use jQuery.
What's the best way of doing this? I'd rather not use window.onload because that requires waiting until the images have loaded which may take time. Obviously, $(document).ready() would have been perfect, but as I said, I can't use jQuery for this.
Thanks
Onload will do the trick. Martin's jQuery approach will be maybe faster.
for(var i=0; i<document.forms.length; i++){
var form = document.forms[i];
form.addEventListener("submit", myListener,false);
}
Just roll your own :) here is the code that jQuery uses to have the ready event, take what you need, it's free (but do mention in your code where it came from ;)
bindReady: function() {
if ( readyList ) {
return;
}
readyList = jQuery._Deferred();
// Catch cases where $(document).ready() is called after the
// browser event has already occurred.
if ( document.readyState === "complete" ) {
// Handle it asynchronously to allow scripts the opportunity to delay ready
return setTimeout( jQuery.ready, 1 );
}
// Mozilla, Opera and webkit nightlies currently support this event
if ( document.addEventListener ) {
// Use the handy event callback
document.addEventListener( "DOMContentLoaded", DOMContentLoaded, false );
// A fallback to window.onload, that will always work
window.addEventListener( "load", jQuery.ready, false );
// If IE event model is used
} else if ( document.attachEvent ) {
// ensure firing before onload,
// maybe late but safe also for iframes
document.attachEvent( "onreadystatechange", DOMContentLoaded );
// A fallback to window.onload, that will always work
window.attachEvent( "onload", jQuery.ready );
// If IE and not a frame
// continually check to see if the document is ready
var toplevel = false;
try {
toplevel = window.frameElement == null;
} catch(e) {}
if ( document.documentElement.doScroll && toplevel ) {
doScrollCheck();
}
}
},
in jquery $(document).ready(function) or $(function) , how could I do the same thing without jquery, and I need browser compatiable, and allow to attach more than one function.
Note: dom ready!= window onload
This is the way jQuery wraps the functions you're looking for - the snippet does not need jQuery, and is cross-browser compatible. I've replaced all calls to jQuery.ready() with yourcallback - which you need to define.
What goes on in here:
first, the function DOMContentLoaded is defined, which will be used when the DOMContentLoaded event fires - it ensures that the callback is only called once.
a check if the document is already loaded - if yes, fire the callback right away
otherwise sniff for features (document.addEventListener / document.attachEvent) and bind the callbacks to it (different for IE and normal browsers, plus the onload callback)
Lifted from jQuery 1.4.3, functions bindReady() and DOMContentLoaded:
/*
* Copyright 2010, John Resig
* Dual licensed under the MIT or GPL Version 2 licenses.
* http://jquery.org/license
*/
// Cleanup functions for the document ready method
// attached in the bindReady handler
if ( document.addEventListener ) {
DOMContentLoaded = function() {
document.removeEventListener( "DOMContentLoaded", DOMContentLoaded, false );
//jQuery.ready();
yourcallback();
};
} else if ( document.attachEvent ) {
DOMContentLoaded = function() {
// Make sure body exists, at least, in case IE gets a little overzealous
if ( document.readyState === "complete" ) {
document.detachEvent( "onreadystatechange", DOMContentLoaded );
//jQuery.ready();
yourcallback();
}
};
}
// Catch cases where $(document).ready() is called after the
// browser event has already occurred.
if ( document.readyState === "complete" ) {
// Handle it asynchronously to allow scripts the opportunity to delay ready
//return setTimeout( jQuery.ready, 1 );
// ^^ you may want to call *your* function here, similarly for the other calls to jQuery.ready
setTimeout( yourcallback, 1 );
}
// Mozilla, Opera and webkit nightlies currently support this event
if ( document.addEventListener ) {
// Use the handy event callback
document.addEventListener( "DOMContentLoaded", DOMContentLoaded, false );
// A fallback to window.onload, that will always work
//window.addEventListener( "load", jQuery.ready, false );
window.addEventListener( "load", yourcallback, false );
// If IE event model is used
} else if ( document.attachEvent ) {
// ensure firing before onload,
// maybe late but safe also for iframes
document.attachEvent("onreadystatechange", DOMContentLoaded);
// A fallback to window.onload, that will always work
window.attachEvent( "onload", yourcallback );
}
That's 51 lines of pure JavaScript code, just to register the event reliably. As far as I know, there is no easier method. Goes to show what the wrappers like jQuery are good for: they wrap the capability sniffing and ugly compatibility issues so that you can focus on something else.
Smallest DOMReady code, ever.
<html>
<head>
<script>
var ready = function (f) {
(/complete|loaded|interactive/.test(document.readyState)) ?
f() :
setTimeout(ready, 9, f);
};
</script>
</head>
<body>
<script>
ready(function () {
alert('DOM Ready!');
});
</script>
</body>
</html>
This is all you need if you're supporting IE9+ and modern (2013) versions of Chrome, FF, Safari, etc.
function ready(event) {
// your code here
console.log('The DOM is ready.', event);
// clean up event binding
window.removeEventListener('DOMContentLoaded', ready);
}
// bind to the load event
window.addEventListener('DOMContentLoaded', ready);
Here's a method I use that seems to work reliably
function ready(func) {
var span = document.createElement('span');
var ms = 0;
setTimeout(function() {
try {
document.body.appendChild(span);
document.body.removeChild(span);
//Still here? Then document is ready
func();
} catch(e) {
//Whoops, document is not ready yet, try again...
setTimeout(arguments.callee, ms);
}
}, ms);
}
Pretty simple, it just keeps trying to append an empty <span> element to document.body. If the document is not "ready" an exception will be thrown, in which case it tries again with a new setTimeout call. Once no exception is thrown, it calls the callback function.
I'd be happy to hear if there are any problems with this method. It has worked well for me, but I have not done the extensive testing that would be natural to any popular Javascript framework.
I've seen lots of different ways of trying to do this. The simplest way (suggested by yahoo initially, I think) is to just call your initializer function after the close body tag, a bit obtrusive, but it's a single line.
Edit
The DomReady event does not exist nativly in javascript. You can implement your own by following some wonderful work done by people like Dean Edwards here and here with those in place you can perform a similar event attachment process on document instead of window.
Check out user83421's answer to How do I add an additional window.onload event in Javascript
To recap here as well.
if (window.addEventListener) // W3C standard
{
window.addEventListener('load', myFunction, false); // NB **not** 'onload'
}
else if (window.attachEvent) // Microsoft
{
window.attachEvent('onload', myFunction);
}
I have this after the 'close body' tag and before the 'close html' tag. and it works pretty well. The load presets function assigns width,height and position values to css div tags. useful for different screen sizes.
document.onreadystatechange = function () {
if (document.readyState == "interactive") {
loadPresets();
}
}