Javascript domready?
Asked Answered
N

11

52

I know I can use different frameworks like prototype or jQuery to attach a function to the window.onload, but's not what I'm looking for.

I need something like .readyState so that I can do something like this:

if(document.isReady){
  var id = document.getElem ...
}

is there any other way than using what the frameworks do?

Nicholenicholl answered 30/7, 2009 at 14:25 Comment(6)
Detecting DOM ready reliably cross-browser is not trivial. Why don't you want to use one of the proven frameworks?Willetta
i would recommend looking at domassistant - it is very lightweight library. or, check d-lite for extra lightweight set of functions.Electrodeposit
I have been asked not to, basically.Nicholenicholl
See my answer on a similar question for the link to a cross-browser DOMReady object.Cronk
you may want to reconsider the correct answer.Rayburn
agree with @PatrickW.McMahon, the correct answer should be, as of 2017, to use the standard document.addEventListener('DOMContentLoaded' ..., as suggested below (almost hidden), instead of a library.Testicle
T
11

i've updated the code of DOMAssistant library it works fine with me

var domReady = (function (){
  var arrDomReadyCallBacks = [] ;
  function excuteDomReadyCallBacks(){
       for (var i=0; i < arrDomReadyCallBacks.length; i++) {
         arrDomReadyCallBacks[i]();
       }
       arrDomReadyCallBacks = [] ;
  }

  return function (callback){
    arrDomReadyCallBacks.push(callback);
     /* Mozilla, Chrome, Opera */
      if (document.addEventListener ) {
          document.addEventListener('DOMContentLoaded', excuteDomReadyCallBacks, false);
      }
    /* Safari, iCab, Konqueror */
    if (/KHTML|WebKit|iCab/i.test(navigator.userAgent)) {
        browserTypeSet = true ;
        var DOMLoadTimer = setInterval(function () {
            if (/loaded|complete/i.test(document.readyState)) {
                //callback();
                excuteDomReadyCallBacks();
                clearInterval(DOMLoadTimer);
            }
        }, 10);
    }
    /* Other web browsers */

    window.onload = excuteDomReadyCallBacks;
}
})()
Tonita answered 12/8, 2013 at 17:54 Comment(2)
why the down voting ? the code is tested with ie 8 ,firefox and chrome .Tonita
Your example is a Rube Goldberg Machine. Remember in programming the KISS method. There are simple one liner solutions to solving the problem without the need of extra processing. Please add more documentation as to why your solution is needed over simpler one line solutions. Code snippets without documents don't get a lot of up votes.Rayburn
P
44

Edit: As the year 2018 comes upon us, I think it's safe to listen for the DOMContentLoaded event.

function fireOnReady() { /* ... */ }
if (document.readyState === 'complete') {
    fireOnReady();
} else {
    document.addEventListener("DOMContentLoaded", fireOnReady);
}

Please note, the event will only fire once when your page loads! If you have to support really old browsers, then check out the super lightweight script I put together below.



For historical reference only:



jQuery has an undocumented property called isReady which is used internally to determine whether the DOM ready event has fired:

if($.isReady) {
    // DOM is ready
} else {
    // DOM is not yet ready
}

I started at 1.5.2 went back as far as 1.3.2 and the property is there. While undocumented, I would say that you can rely on this property in future versions of jQuery. Edit: And a year later - v1.7.2, they still use $.isReady - still undocumented, so please use at your own risk. Be careful when upgrading.

Edit: v1.9, they still use $.isReady - still undocumented

Edit: v2.0, with all of it's "major" changes, still uses $.isReady - still undocumented

Edit: v3.x still uses $.isReady - still undocumented

Edit: As several people have pointed out, the above does not really answer the question. So I have just created a mini DOM ready snippet which was inspired by Dustin Diaz's even smaller DOM ready snippet. Dustin created a neat way to check the document readyState with something similar to this:

if( !/in/.test(document.readyState) ) {
    // document is ready
} else {
    // document is NOT ready
}

The reason this works is because the browser has 3 loading states: "loading", "interactive", and "complete" (older WebKit also used "loaded", but you don't have to worry about that any more). You will notice that both "loading" and "interactive" contain the text "in"... so if the string "in" is found inside of document.readyState, then we know we are not ready yet.

Parisian answered 13/6, 2011 at 16:56 Comment(7)
Not sure why the down vote. I explained that this is undocumented. Debugging this issue in future versions of jQuery would be extremely simple, and it's one of those self-describing variables that will never pass the "there's a better name for this" test and therefore will likely never get renamed. whatever... I wish people would explain down votes.Parisian
This doesn't answer the question (OP doesn't want to use a framework). It does, however, provide a good answer to a question marked as "exact duplicate" of this one (+1 from me). #8374410Arthropod
Upvoted- does not answer this question, but answers questions of many people ending up here.Grappling
The requirement was to get dom ready without using a framework. Your example solves the problem but using a framework. This should be part of a different question asking how to get dom ready using JQuery but should not be a solution to the current question. Do not up vote something for solving another question. Only up vote when it solves the current question.Rayburn
@et al - This was one of my earliest answers on S.O. and I was not wise in my ways. Thanks to those who pointed out my shortsightedness, I have long since updated my answer to include a framework-less solution.Parisian
Upvote for admitting shortsightedness and correcting it thereto.Venuti
Thank you for correcting your answer so that it meets the requirements of the question.Rayburn
D
32

While I usually advocate avoiding using frameworks unless necessary, I'd say using one in this case is perfectly fine. Here's jQuery:

$(function () {
    // do stuff after DOM has loaded
});

Note that it is NOT the same as an window.onload event, since onload executes first after other resources have been loaded (images etc.) The code I used in my example will execute when the DOM has finished loading, i.e., when the full HTML structure is available (not necessarily when images, CSS, etc. is available.)

If you want a checkable variable, you can set one in the ready-function:

var documentIsReady = false;
$(function () { documentIsReady = true; });

Of course you can find even more light-weight libraries than jQuery if all you want to do is to check for DOM-ready. But use a library in cases where different browsers behave very differently (this is one such case.)

Using some code from the DOMAssistant library, making your own "DOM is ready" function shouldn't be too hard:

var domLoaded = function (callback) {
    /* Internet Explorer */
    /*@cc_on
    @if (@_win32 || @_win64)
        document.write('<script id="ieScriptLoad" defer src="//:"><\/script>');
        document.getElementById('ieScriptLoad').onreadystatechange = function() {
            if (this.readyState == 'complete') {
                callback();
            }
        };
    @end @*/
    /* Mozilla, Chrome, Opera */
    if (document.addEventListener) {
        document.addEventListener('DOMContentLoaded', callback, false);
    }
    /* Safari, iCab, Konqueror */
    if (/KHTML|WebKit|iCab/i.test(navigator.userAgent)) {
        var DOMLoadTimer = setInterval(function () {
            if (/loaded|complete/i.test(document.readyState)) {
                callback();
                clearInterval(DOMLoadTimer);
            }
        }, 10);
    }
    /* Other web browsers */
    window.onload = callback;
};

Not tested, but it should work. I simplified it from DOMAssistant, because DOMAssistant allows multiple callbacks and has checking to make sure you can't add the same function twice etc.

Desmid answered 30/7, 2009 at 14:33 Comment(9)
It's the only thing I need from a framework, everything else it has to serve, I don't need, so if possible, I would prefer not to use a framework in this case, otherwise I would go with jqueryNicholenicholl
Okay, I added some simplified code from DOMAssistant, you could try that. According to their site it should work in all the major browsers. domassistant.com/documentation/DOMAssistantLoad-module.phpDesmid
My code will call callback up to two times (since window.onload should execute in all browsers.) When handling the event, check if callback has already been called and return if it has (this is what DOMAssistant does but I removed that part.)Desmid
changing the value of window.onload without respect the actual value can produce unexpected behaviors in the code of other scripts. Also we can not call domLoaded twice since only the last one will be used.Scenery
This code worked for me! Except I had to use else if or firefox would fire twice.Gustaf
if (/loaded|complete/i.test(document.readyState)) { callback(); return; } should be at the top of the function in case the page has already been loaded.Anacrusis
This, unlike jQuery's domready, will not add callbacks! At least for the window.onload, it will only replace existing callbacks with a new one!Holtorf
+1 for not saying just use jquery or x library I hate when people do this.Lipinski
DOMContentLoaded fires one time when the DOM is fully loaded and parsed. all the extra stuff you're doing is not needed.Rayburn
L
32

In the 5 years that have passed since this question was asked DOMContentLoaded has become a universally supported event, and you can just use that.

document.addEventListener('DOMContentLoaded', function() {
    //.. do stuff ..
}, false);
Lamellicorn answered 4/2, 2015 at 5:12 Comment(4)
I was just getting ready make a comment about DOMContentLoaded myself. Since there aren't any dissenting opinions here, I assume this is the right way to go?Buehrer
This is supported in every modern browser caniuse.com/#search=DOMContentLoadedBlackman
Why did you post this a year after people had already commented on the addEventListener(). You have not added anything that other answers prior to yours had already done.Rayburn
Well, sorry Patrick I know it seems like I deliberately re-answered this question in the same way as you in order to steal your internet points but I honestly didn't see your answer. I scrolled through at the time and thought well that's funny, no one has pointed out that this is no longer an issue that requires 3rd party code. Which is still, I think, the part of my answer that people are upvoting - that this is now universally supported.Lamellicorn
T
11

i've updated the code of DOMAssistant library it works fine with me

var domReady = (function (){
  var arrDomReadyCallBacks = [] ;
  function excuteDomReadyCallBacks(){
       for (var i=0; i < arrDomReadyCallBacks.length; i++) {
         arrDomReadyCallBacks[i]();
       }
       arrDomReadyCallBacks = [] ;
  }

  return function (callback){
    arrDomReadyCallBacks.push(callback);
     /* Mozilla, Chrome, Opera */
      if (document.addEventListener ) {
          document.addEventListener('DOMContentLoaded', excuteDomReadyCallBacks, false);
      }
    /* Safari, iCab, Konqueror */
    if (/KHTML|WebKit|iCab/i.test(navigator.userAgent)) {
        browserTypeSet = true ;
        var DOMLoadTimer = setInterval(function () {
            if (/loaded|complete/i.test(document.readyState)) {
                //callback();
                excuteDomReadyCallBacks();
                clearInterval(DOMLoadTimer);
            }
        }, 10);
    }
    /* Other web browsers */

    window.onload = excuteDomReadyCallBacks;
}
})()
Tonita answered 12/8, 2013 at 17:54 Comment(2)
why the down voting ? the code is tested with ie 8 ,firefox and chrome .Tonita
Your example is a Rube Goldberg Machine. Remember in programming the KISS method. There are simple one liner solutions to solving the problem without the need of extra processing. Please add more documentation as to why your solution is needed over simpler one line solutions. Code snippets without documents don't get a lot of up votes.Rayburn
N
10

Check out this demo from microsoft. -> http://ie.microsoft.com/testdrive/HTML5/DOMContentLoaded/Default.html And here is the gist of the code that allows you to run JS on DOM ready...

(function () {
    function load2(){
        // put whatever you need to load on DOM ready in here
        document.getElementById("but3").addEventListener("click", doMore, false);
    }
    if (window.addEventListener) {
        window.addEventListener('DOMContentLoaded', load2, false);
    } else {
        window.attachEvent('onload', load2);
    }
} ());

Here is the some of the javascript source for the demo.. http://ie.microsoft.com/testdrive/Includes/Script/ReturnAndShareControls.js

It works well. Nice!!.. on google Chrome and IE 9.

Newspaperman answered 30/10, 2011 at 23:30 Comment(3)
I believe this should be document.addEventListener(... not windowLuttrell
@Luttrell Sorry but I have not used the code in my post for too long to recall it well enough. Perhaps browser updates have made for the change you suggest.Newspaperman
you don't need the false at the end of addEventListener('DOMContentLoaded', load2, false) DOMContentLoaded has no parent item to traverse.Rayburn
R
10
document.addEventListener("DOMContentLoaded", function(e){
    console.log("dom ready");//output to web browser console
});

no JQuery needed for this. There is no need to pass the 3rd parameter on a DOMContentLoaded as this event has no parent to traverse the event. Also no need to get all fancy with what everyone else is saying. This will tell you when the DOM is fully loaded and ready to use. I LOLed when i noticed the DOM assistant lib. That lib is absolutely useless.

The DOMContentLoaded event is fired when the document has been completely loaded and parsed, without waiting for stylesheets, images, and subframes to finish loading

addEventListener() is a great function for checking any event including DOM ready status. When using "DOMContentLoaded" the 3rd parameter in addEventListener() is not needed as this trigger has no parent item to pass the event too. In my above example you will notice the 2nd parameter is an anonymous function. You can also pass the name of a function into the 2nd parameter.

document.addEventListener([(string)event trigger], [function],[(boolean)traverse DOM tree]);

Another benefit to using this over JQuery is this will not break when you update JQuery.

Rayburn answered 29/8, 2014 at 14:11 Comment(0)
V
6

jQuery doesn't use window.onload.

$(document).ready() waits until the DOM has loaded and can be traversed (the rest of the content may or may not be loaded by that point).

If you pull up the source for jQuery and sort through the mess, you'll find the work is done by the bindReady() method which has several different implementations for different browsers and only when all of those implementations fail does it fall back on listening for the load event for the window.

Vehement answered 30/7, 2009 at 14:31 Comment(7)
@PatrickW.McMahon - I didn't suggest using jQuery in my answer. If you read it closer, I told the OP to read the source of jQuery to see how they're doing their ready detection so that he could mimic it.Vehement
Why tell some one to dig into jQuery code for something when you can link them to w3schools documentation for getting DOM state? It takes less time to do and no need to dig into thousands of lines of JQuery and following JQuery flags and triggers just to find out they wrapped the w3school demo into a JQuery function. The simple solution is normally the best solution. A programmers time is valuable. Pick the most effective solution. By the time he had dug into the JQuery framework he may as well just used JQuery.Rayburn
@PatrickW.McMahon - No need to look at thousands of lines. I told the OP in my answer exactly which method to look at. W3Schools isn't going to show the OP the best way to implement identical functionality in each browser. If you want to be a better developer, you learn from good code. W3Schools certainly doesn't have good code.Vehement
@Justin Niessner - W3School is the governing body for the web. If you think they're not providing good quality code to the standards they made then we have bigger problems on our hands. The members that run W3School are the same people that are working on the new HTML5 standards.Rayburn
@PatrickW.McMahon - W3School is certainly NOT the governing body of the web. That would be the W3C (World Wide Web Consortium) w3.org W3Schools has gotten better than it was, but there are still issues. Check out w3fools.com for more info.Vehement
A lot of the people working for W3School are members of W3C. I'm not saying all members of W3C work for W3School, but W3School has many of its employees as members of W3C. So they often have the information as its being published by W3C. I was not able to find them on the list w3.org/Consortium/Member/List but I beleave they are under a corporate name. Not by the sites name.Rayburn
@PatrickW.McMahon - W3Schools was created and is still owned by Refsnes Data. They are not a member of the W3C. Furthermore, it is publicly stated that W3Schools is, in no way, affiliated with the W3C. If you have a list of W3C members employed by Refsnes Data, I'd be very appreciative to see it.Vehement
B
3

This is actually one of the biggest reasons most people use frameworks like jQuery because the solution to this is not consistent across browsers.

Batory answered 30/7, 2009 at 14:31 Comment(3)
I know, and I am a heavy user of jquery myself, but in this case I do not want to rely on a framework, I have been asked to avoid it.Nicholenicholl
I would suggest possibly looking at the source to jQuery and porting just the code you want into your project.Batory
getting DOM ready is a single line document.addEventListener("DOMContentLoaded", function(e){/*dom ready do something*/}); how is that so hard that you need to use a framework to get dom ready?Rayburn
U
1

Try this:
Link: onDomReady at GitHub or the source below:

if(document.ondomready == undefined) {
    document.ondomready = {};
    document.ondomready = null;
} else {
    document.ondomready=document.ondomready;
}
var oldonload=document.onload;
var isLaunched = 0;
document.onload = function() {  
    if(oldonload !== null) {
        oldonload.call();
    }
};
document.addEventListener("DOMContentLoaded", function onDom(evt) {
    var olddomready = document.ondomready;
    if(olddomready !== null) {
        if(isLaunched == 0) {
            olddomready.call(evt);
            isLaunched == 1;
            //We now launched the mapped DOMContentLoaded Event
        } else {
            //We already launched DOMContentLoaded Event
        }
    }
}, false);

I've already tested this on Opera 11.x/12.x. Not yet tested on others. Let me know if they do.

Note: I haven't yet uploaded the repository, but I will soon in my spare time.

Ureter answered 29/6, 2012 at 22:2 Comment(1)
"DOMContentLoaded" fires one time when the DOM is fully loaded and parsed. all of the extra stuff you added in is doing nothing.Rayburn
D
0

If you want smaller libs which does only particular things, you could use libs in microjs. For the question at hand DOMStatic libs ready method can be used.

Description answered 1/12, 2014 at 22:10 Comment(0)
H
0

It seems this question was asked a reallly long time ago. Today we now have document.readyState, and even an event that goes with it.

To achieve the equivalent of:

if(document.isReady){
  var id = document.getElem ...
}

Use the following:

const doTask = () => {
  var id = document.getElem ....
}

if (document.readyState !== 'loading') {
  // in case we missed the `loading` state, start running the
  // task now...
  doTask();
} else {
  //  otherwise register a listener to be notified of the next state
  document.addEventListener('readystatechange', event => {
    if (event.target.readyState === 'interactive') {
      doTask();
    }
  });
}

The other answers which use window:DOMContentLoaded event, will receive that event after the above event listener runs, which means that using the readystatechange event allows you to start working on the DOM before DOMContentLoaded is fired, while still being able to interact with DOM elements.

The MDN docs provide an example here. Just in case the example goes away, here it is:

const log = document.querySelector('.event-log-contents');
const reload = document.querySelector('#reload');

reload.addEventListener('click', () => {
  log.textContent ='';
  window.setTimeout(() => {
      window.location.reload(true);
  }, 200);
});

window.addEventListener('load', (event) => {
    log.textContent = log.textContent + 'load\n';
});

document.addEventListener('readystatechange', (event) => {
    log.textContent = log.textContent + `readystate: ${document.readyState}\n`;
});

document.addEventListener('DOMContentLoaded', (event) => {
    log.textContent = log.textContent + `DOMContentLoaded\n`;
});
<div class="controls">
  <button id="reload" type="button">Reload</button>
</div>

<div class="event-log">
  <label>Event log:</label>
  <textarea readonly class="event-log-contents" rows="8" cols="30"></textarea>
</div>
Huertas answered 10/7, 2022 at 5:3 Comment(0)

© 2022 - 2024 — McMap. All rights reserved.