Code inside DOMContentLoaded event not working - javascript

I have used
<!DOCTYPE html>
<html>
<head>
<meta charset="utf-8" />
</head>
<body>
<button type="button" id="button">Click</button>
<pre id="output">Not Loading...</pre>
<script src="https://cdnjs.cloudflare.com/ajax/libs/babel-standalone/6.17.0/babel.min.js"></script>
<script type="text/babel">
document.addEventListener('DOMContentLoaded', function () {
const button = document.getElementById('button');
const output = document.getElementById('output');
output.textContent = 'Loading...';
addEventListener('click', function () {
output.textContent = 'Done';
});
});
</script>
</body>
</html>
but it seems the code inside document.addEventListener('DOMContentLoaded', function () {}); is not loading.
If I remove this from my code, it suddenly works.
I have made a JS Bin here.

It's most likely because the DOMContentLoaded event was already fired at this point. The best practice in general is to check for document.readyState to determine whether or not you need to listen for that event at all.
if (document.readyState !== 'loading') {
console.log('document is already ready, just execute code here');
myInitCode();
} else {
document.addEventListener('DOMContentLoaded', function () {
console.log('document was not ready, place code here');
myInitCode();
});
}
function myInitCode() {}

The event has already fired by the time that code hooks it. The way Babel standalone works is by responding to DOMContentLoaded by finding and executing all of the type="text/babel" scripts on the page. You can see this in the index.js file:
// Listen for load event if we're in a browser and then kick off finding and
// running of scripts with "text/babel" type.
const transformScriptTags = () => runScripts(transform);
if (typeof window !== 'undefined' && window && window.addEventListener) {
window.addEventListener('DOMContentLoaded', transformScriptTags, false);
}
Just run the code directly, without waiting for the event, since you know Babel standalone will wait for it for you.
Also note that if you put you script at the end of the body, just before the closing </body> tag, there's no need to wait for DOMContentLoaded even if you don't use Babel. All of the elements defined above the script will exist and be available to your script.
In a comment you've asked:
But I am using Babel standalone in development, but I will pre-compile it when I go into production. Should I add it back on when I go into production?
Just ensure that your script tag is at the end of body as described above, and there's no need to use the event.
If it's important to you to use it anyway, you can check to see whether the event has already run by checking document.readyState (after following the link, scroll up a bit):
function onReady() {
// ...your code here...
}
if (document.readyState !== "loading") {
onReady(); // Or setTimeout(onReady, 0); if you want it consistently async
} else {
document.addEventListener("DOMContentLoaded", onReady);
}
document.readyState goes through these stages (scroll up slightly from the link above):
Returns "loading" while the Document is loading, "interactive" once it is finished parsing but still loading sub-resources, and "complete" once it has loaded.

Another option would be to use the readystatechange event. The readystatechange event fires when the readyState attribute of the document has changed. The readyState attribute can be one of the following three values: 'loading', 'interactive', or 'complete'. An alternative to using the DOMContentLoaded event is to look for the readyState to equal 'interactive' inside of the document's readystatechange event, as in the following snippet.
document.onreadystatechange = function () {
if (document.readyState === 'interactive') {
// Execute code here
}
}
Although, in your case, the document's readyState seems to have already reached 'complete'. In that case, you can simply swap 'interactive' for 'complete' in the snippet above. This is technically equal to the load event instead of the DOMContentLoaded event.
Read more on MDN,
Document.readyState
Document: readystatechange event

Thanks to Ruslan & here is the full code snippet with the convenient detach of the DOMContentLoaded handler after it is used.
'use strict';
var dclhandler = false;
if (document.readyState !== 'loading') {
start();
} else {
dclhandler = true;
document.addEventListener('DOMContentLoaded', start);
}
function start() {
if (dclhandler) { document.removeEventListener('DOMContentLoaded', start); }
console.log('Start the site`s JS activities');
}

I also encountered the same problem when I enable both HTML Auto Minify and Rocket Loader in Cloudflare. the conclusion is that DOMContentLoaded event is missing when handled by these features simultaneously.
You can add the following code before all DOMContentLoaded event listeners in the HTML file script block to fix this.
var inCloudFlare = true;
window.addEventListener("DOMContentLoaded", function () {
inCloudFlare = false;
});
if (document.readyState === "loading") {
window.addEventListener("load", function () {
if (inCloudFlare) window.dispatchEvent(new Event("DOMContentLoaded"));
});
}
For explanation please go to my blog.
https://hollowmansblog.wordpress.com/2021/10/18/solution-to-missing-domcontentloaded-event-when-enabling-both-html-auto-minify-and-rocket-loader-in-cloudflare/

My clean aproach...
if (document.readyState !== 'loading') init()
else document.addEventListener('DOMContentLoaded', init);
function init() {
console.log("Do it !");
...
}

I would use document.addEventListener("DOMContentLoaded", () => {/*yourcode*/});

https://learnwithparam.com/blog/vanilla-js-equivalent-of-jquery-ready/
function ready(callbackFunc) {
if (document.readyState !== 'loading') {
// Document is already ready, call the callback directly
callbackFunc();
} else if (document.addEventListener) {
// All modern browsers to register DOMContentLoaded
document.addEventListener('DOMContentLoaded', callbackFunc);
} else {
// Old IE browsers
document.attachEvent('onreadystatechange', function() {
if (document.readyState === 'complete') {
callbackFunc();
}
});
}
}
ready(function() {
// your code here
});

DOMContentLoaded event is working in when we call it from script tag. But that event not working in js file

I've come into this problem with my live server.
My live server is running on cloudflare with some cache and rocket loading js. I assume this is what is causing the unexpected behaviour.
The code was working perfectly on local server when using DOMContentLoaded, but not on live.
If you can use jQuery, switching to
jQuery(document).ready(function() {
//code...
})
work as expected.

Related

How to automatically read a web page when refreshed [duplicate]

This question already has answers here:
How to make JavaScript execute after page load?
(25 answers)
Closed 1 year ago.
I am using following code to execute some statements after page load.
<script type="text/javascript">
window.onload = function () {
newInvite();
document.ag.src="b.jpg";
}
</script>
But this code does not work properly. The function is called even if some images or elements are loading. What I want is to call the function the the page is loaded completely.
this may work for you :
document.addEventListener('DOMContentLoaded', function() {
// your code here
}, false);
or
if your comfort with jquery,
$(document).ready(function(){
// your code
});
$(document).ready() fires on DOMContentLoaded, but this event is not being fired consistently among browsers. This is why jQuery will most probably implement some heavy workarounds to support all the browsers. And this will make it very difficult to "exactly" simulate the behavior using plain Javascript (but not impossible of course).
as Jeffrey Sweeney and J Torres suggested, i think its better to have a setTimeout function, before firing the function like below :
setTimeout(function(){
//your code here
}, 3000);
JavaScript
document.addEventListener('readystatechange', event => {
// When HTML/DOM elements are ready:
if (event.target.readyState === "interactive") { //does same as: ..addEventListener("DOMContentLoaded"..
alert("hi 1");
}
// When window loaded ( external resources are loaded too- `css`,`src`, etc...)
if (event.target.readyState === "complete") {
alert("hi 2");
}
});
same for jQuery:
$(document).ready(function() { //same as: $(function() {
alert("hi 1");
});
$(window).load(function() {
alert("hi 2");
});
NOTE: - Don't use the below markup ( because it overwrites other same-kind declarations ) :
document.onreadystatechange = ...
I'm little bit confuse that what you means by page load completed, "DOM Load" or "Content Load" as well? In a html page load can fire event after two type event.
DOM load: Which ensure the entire DOM tree loaded start to end. But not ensure load the reference content. Suppose you added images by the img tags, so this event ensure that all the img loaded but no the images properly loaded or not. To get this event you should write following way:
document.addEventListener('DOMContentLoaded', function() {
// your code here
}, false);
Or using jQuery:
$(document).ready(function(){
// your code
});
After DOM and Content Load: Which indicate the the DOM and Content load as well. It will ensure not only img tag it will ensure also all images or other relative content loaded. To get this event you should write following way:
window.addEventListener('load', function() {...})
Or using jQuery:
$(window).on('load', function() {
console.log('All assets are loaded')
})
If you can use jQuery, look at load. You could then set your function to run after your element finishes loading.
For example, consider a page with a simple image:
<img src="book.png" alt="Book" id="book" />
The event handler can be bound to the image:
$('#book').load(function() {
// Handler for .load() called.
});
If you need all elements on the current window to load, you can use
$(window).load(function () {
// run code
});
If you cannot use jQuery, the plain Javascript code is essentially the same amount of (if not less) code:
window.onload = function() {
// run code
};
If you wanna call a js function in your html page use onload event. The onload event occurs when the user agent finishes loading a window or all frames within a FRAMESET. This attribute may be used with BODY and FRAMESET elements.
<body onload="callFunction();">
....
</body>
You're best bet as far as I know is to use
window.addEventListener('load', function() {
console.log('All assets loaded')
});
The #1 answer of using the DOMContentLoaded event is a step backwards since the DOM will load before all assets load.
Other answers recommend setTimeout which I would strongly oppose since it is completely subjective to the client's device performance and network connection speed. If someone is on a slow network and/or has a slow cpu, a page could take several to dozens of seconds to load, thus you could not predict how much time setTimeout will need.
As for readystatechange, it fires whenever readyState changes which according to MDN will still be before the load event.
Complete
The state indicates that the load event is about to fire.
This way you can handle the both cases - if the page is already loaded or not:
document.onreadystatechange = function(){
if (document.readyState === "complete") {
myFunction();
}
else {
window.onload = function () {
myFunction();
};
};
}
you can try like this without using jquery
window.addEventListener("load", afterLoaded,false);
function afterLoaded(){
alert("after load")
}
Alternatively you can try below.
$(window).bind("load", function() {
// code here });
This works in all the case. This will trigger only when the entire page is loaded.
window.onload = () => {
// run in onload
setTimeout(() => {
// onload finished.
// and execute some code here like stat performance.
}, 10)
}
If you're already using jQuery, you could try this:
$(window).bind("load", function() {
// code here
});
I can tell you that the best answer I found is to put a "driver" script just after the </body> command. It is the easiest and, probably, more universal than some of the solutions, above.
The plan: On my page is a table. I write the page with the table out to the browser, then sort it with JS. The user can resort it by clicking column headers.
After the table is ended a </tbody> command, and the body is ended, I use the following line to invoke the sorting JS to sort the table by column 3. I got the sorting script off of the web so it is not reproduced here. For at least the next year, you can see this in operation, including the JS, at static29.ILikeTheInternet.com. Click "here" at the bottom of the page. That will bring up another page with the table and scripts. You can see it put up the data then quickly sort it. I need to speed it up a little but the basics are there now.
</tbody></body><script type='text/javascript'>sortNum(3);</script></html>
MakerMikey
I tend to use the following pattern to check for the document to complete loading. The function returns a Promise (if you need to support IE, include the polyfill) that resolves once the document completes loading. It uses setInterval underneath because a similar implementation with setTimeout could result in a very deep stack.
function getDocReadyPromise()
{
function promiseDocReady(resolve)
{
function checkDocReady()
{
if (document.readyState === "complete")
{
clearInterval(intervalDocReady);
resolve();
}
}
var intervalDocReady = setInterval(checkDocReady, 10);
}
return new Promise(promiseDocReady);
}
Of course, if you don't have to support IE:
const getDocReadyPromise = () =>
{
const promiseDocReady = (resolve) =>
{
const checkDocReady = () =>
((document.readyState === "complete") && (clearInterval(intervalDocReady) || resolve()));
let intervalDocReady = setInterval(checkDocReady, 10);
}
return new Promise(promiseDocReady);
}
With that function, you can do the following:
getDocReadyPromise().then(whatIveBeenWaitingToDo);
call a function after complete page load set time out
setTimeout(function() {
var val = $('.GridStyle tr:nth-child(2) td:nth-child(4)').text();
for(var i, j = 0; i = ddl2.options[j]; j++) {
if(i.text == val) {
ddl2.selectedIndex = i.index;
break;
}
}
}, 1000);
Try this jQuery:
$(function() {
// Handler for .ready() called.
});
Put your script after the completion of body tag...it works...

How to return a value with EvaluateScriptAsync() only once the DOM is loaded

I have asked a question not too long ago on how to wait for a script to be executed by cefSharp before continuing my main program and I was advised to use await browser.EvaluateScriptAsync(...) this works fine when I am not using any EventHandler.
But say that I want to wait for the Dom to be loaded before executing my script I would use the following event handler:
window.addEventListener('DOMContentLoaded', (event) => {
console.log('DOM fully loaded and parsed');
});
What I want to do now is return true once the Dom is loaded (and return nothing before).This would theoretically allow my program to wait till the dom is loaded before the execution continues. So what I tried to do was the following :
await browser.EvaluateScriptAsync( "
function returnTrue() {
return true;
}
function waitForDom(callback) {
window.addEventListener('DOMContentLoaded', (event) => {
console.log('hi');
callback();
});
waitForDom(returnTrue);
"};
console.WriteLine("outside");
The expected output would be :
hi
outside
but what I get is :
outside
hi
This implies that my main program doesn't wait for the Dom to be loaded before continuing.
Why does this not work ?
I think you are looking for this
$( document ).ready(function() {
console.log( "ready!" );
});
https://learn.jquery.com/using-jquery-core/document-ready/
or if javascript only
window.onload = function () { alert("It's loaded!") }
https://stackoverflow.com/a/1033448/5517161

mac window load doesn't always fire

My load events do not always fire in safari or chrome on mac (safari version 7.0.5, chrome version 43.0.2357.124). It works fine in firefox and in any of my windows browsers.
window.addEventListener('load', function (){
alert("loaded js");
}, false);
$(window).bind("load", function() {
alert("loaded jquery");
});
Both functions fire or none of them does.
Does someone know what is happening here?
Thanks for help.
Since that JS is in a separate file, I can imagine that at the time it runs, the load event has already been fired.
You can detect this, however, using document.readyState (see also this question).
It has three possible values:
loading - parsing is still going on
interactive - parsing has finished, but resources are loading
complete - pasing has finished and resources have been loaded
I suggest you check whether document.readyState == 'complete' and run your code, otherwise register an event listener:
~function()
{
var loadJS = function()
{
alert("loaded js");
};
var loadJQ = function()
{
alert("loaded jquery");
};
if(document.readyState == 'complete')
{
loadJS();
loadJQ();
}
else
{
window.addEventListener('load', loadJS, false);
$(window).bind('load', loadJQ);
}
}();

How to remove a DOM ready handler so a Javascript function can be fired on

I've made a module in JS (without jQuery) that changes the background image of a web-page based on data from the client browser (getting browser width, height and doing the appropriate stuff.. etc.) but I only know how to initialize it on page load via DOM eventListeners and I want to be able to be able to fire it via click or other user-driven events.
I don't think I'm fully grasping what I need to do to remove the EventListener without making all the rest of the code unusable, which has been the end result of my own attempts.
Any points in the right direction would be much appreciated - below is the first couple of functions called by the script:
// the initialization of the page
bindReady(function(){
startBGResize();
});
// DOM ready handler
function bindReady(handler){
var called = false;
var ready = function() {
if (called) return;
called = true;
handler();
};
if (document.addEventListener) {
document.addEventListener('DOMContentLoaded', ready, false);
} else if (document.attachEvent) {
if (document.documentElement.doScroll && window == window.top) {
var tryScroll = function(){
if (called) return;
if (!document.body) return;
try {
document.documentElement.doScroll('left');
ready();
} catch(e) {
setTimeout(tryScroll, 0);
}
};
tryScroll();
}
document.attachEvent('onreadystatechange', function(){
if (document.readyState === 'complete') {
ready();
}
});
}
if (window.addEventListener) window.addEventListener('load', ready, false);
else if (window.attachEvent) window.attachEvent('onload', ready);
}
If you mean you want to call startBGResize when some element is clicked, you can do it like this:
var element = document.querySelector("CSS selector for the element that you'll click");
if (element.addEventListener) {
element.addEventListener("click", startBGResize, false);
} else if (element.attachEvent) {
element.attachEvent("onclick", startBGResize);
}
That works on all modern browsers, and also IE8.
If you're going to be hooking events regularly (and if you need to support IE8 or "compatibility" mode in later versions of IE), you might want the hookEvent function from this other answer rather than coding the if statement every time (that hookEvent also does things like patch stopPropagation and such).

javascript:how to write $(document).ready like event without jquery

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();
}
}

Categories