Since placing javascript DOM methods in the bottom of the html page (after <body>) is a lot faster than using the jQuery 'ready' event, shouldnt we be forcing it by doing:
$('document').trigger('ready');
...after the body tag? I havent really tried this, but it should speed up things. Or did I miss something?
jQuery.ready();
The ready event means the document has now been parsed and the DOM is available to be manipulated. That happens when the browser has completed its parsing, and you can't make it happen sooner.
How do you think such a thing would work? Would it flip a magic switch in the browser's HTML parser that makes it run faster than it normally does? Would it cause the computer's processor to run faster, so the browser would finish parsing the document sooner?
You can't force the browser to parse the document any faster than it's going to anyway. Not even with jQuery ;-)
I had a closely related question, I ended up finding the answer myself right before resorting to posting to SO. As people who have my question will likely land here (number one google result for "jquery force document ready"), allow me to give some extra info.
My problem is that I am dynamically generating some HTML (using XSLT) that will sometimes be saved for later, but other times I just want to open a new window with the new HTML so the user can preview it. Like so:
var html = UseXSLTToGenerateSomeHTML();
var myWindow = window.open('', '', 'width=805,height=493');
myWindow.document.write(html);
myWindow.focus();
Problem is, the generated HTML uses jQuery, and the domready event was never getting invoked. It should have been obvious to me immediately from David's answer how to do it, but the tweak escaped me momentarily. It is:
var html = UseXSLTToGenerateSomeHTML();
var myWindow = window.open('', '', 'width=805,height=493');
myWindow.document.write(html);
myWindow.focus();
mywindow.jQuery.ready();
Note that in this case, the page doing this doesn't even use jQuery... only the generated HTML does. Doesn't matter, you are generating the jQuery event on the other document.
Related
I've written a small HTML5 page that I need to be able to support multiple languages. I've implemented the language control by making the page load a JSON file into memory (in the HEAD) and then running a jQuery command to change the text of any element as required.
Everything works fine except that as the change is being called post render (if the document ready function) there is a slight flash as the language gets changed.
Is there an event that is called before the page is rendered but after the DOM is available? If not, are there any suggestions to change implementation.
Cheers..
UPDATE
I've found a few answers to this on other sites. The general consensus appears to be that this isn't possible as most browsers render as they parse. The workaround that is suggested is to hide (display:'none') the body in script and then show it (display:'') after the updates in the document ready function. It sort of works for me although isn't 100% perfect.
Sounds like you are having an issue with FOUC (Flash Of Unstyled Content)
There are a few ways to get around it. You could add this to your body:
<body class="fouc">
And then have this CSS:
.fouc{display:none;}
And finally this script:
$(function(){
$('.fouc').show();
});
This works by initially hiding the page, and then once you are ready, turning it on with javascript. You may need to ensure your manipulation occurs ahead of the $('.fouc').show(); call.
One effective solution, though not the one you are probably looking for, is to use OUTPUT BUFFERING ... What is output buffering?
I'm attempting to insert a snippet into an iframe through jQuery with the following:
var snippet = "<script>document.writeln('test')</script>";
jQuery('<iframe />').appendTo('body').append(snippet);
instead of writing "test" in the iframe, it overwrites the parent window.
How can I make it so that the parent window gets the iframe with "test" inserted in it?
You should set the source of new windows and iframes to 'about:blank' if you want control over them. Then reference it by the iframe's ID!
You also want to use iframe.contentDocument || iframe.contentWindow.document
And it might be a good idea to 'open()' the document before you 'write()' to it.
Update: forgot this: If you open the window about:blank, it needs time to load..
So you cannot write to it right away!!
So either set timeout of about 50ms (usually) and then write to the new window/iframe.
OR check if it is loaded (onload), then have it write the source (I prefer this).
If you need to reuse the iframe, set it to about:blank first (again) and wait or check onload again before writing to the frame again. All this is due to xss security.
I also strongly advise to use the traditional event-model (so no addEvent things, they don't work as intended crossbrowser and lead to memoryleaks in IE).
So: create iframe with src set to about:blank, add a onload function that checks a var containing your html-string: if it is empty, else: write it to the iframe and empty the string.
To update the iframe: set content to the var containing the html-string, followed by setting the source of the iframe to about:blank.
Understand the loop?
This baby even works in IE6...
Good luck!!
UPDATE: you did not escape your snippet properly: should be: <script>document.writeln('test')\<\/script>
See: jsfiddle
UPDATE2: argl.. I normally never give up, but since I don't care for jQuery, I'm not going through the manual for jQuery for something something so simple in something as difficult as jQuery (sorry). For modern (crappy) security reasons you need an about:blank. Period.
See this updated fiddle for the 'plain jane' basics at work, then see how to do it in jquery and make a choice: onload or setTimeout. I'm working on my own crossbrowser html-editor and this subject took over a week to figure out.
I want to call some JS after the page-load, this may involve a delay and as such I want the page loaded first so content is shown... but it seems that the code in onLoad handler is called before the rendering is complete. Is there a better event I can use, which is triggered when the page is 'finished'?
To clarify, I want to run some JS after the page is rendered on-screen, so a 'post-everything event' really.
There are several points of interest along the time sequence. This generic sequence is a good overview, even though different browsers and versions implement the details a little differently. (This assumes you're using raw Javascript and need to minimize cross-browser issues; with it's comprehensive internal handling of cross-browser issues JQuery is a little different):
T0] page-begun-- The browser has started working on the page, but otherwise the environment is in flux. Your JS operations may occur in the wrong context, and simply be flushed away when the right context stabilizes. You probably don't want to try to execute any JS at all.
T1] "onLoad" event-- [however you get events: addEventListener("Load"..., window.onload=..., etc.] All parts of the page have been identified and downloaded from the server and are in the local system's memory. In order for all parts to be identified, some parsing has already occurred. (Note that "load" is a cognate of "download", not "parse" nor "render".)
You now have the right environment and can begin to execute JS code without fear of losing anything. HOWEVER, operations that try to read or manipulate the HTML [getElementById(..., appendChild(..., etc.] may fail in strange ways, or may appear to work but then disappear, or may do something different than you expected.
T2] DOM-almost-ready-- This hack is very simple and fully cross browser. Just put your JS <script>...</script> at the very end of your HTML, just before the </body> tag. Most things will work right, although attempts to append to or modify the DOM at the very end of the <body> may produce surprising results. This isn't fully correct, but it works 99% of the time. Given its simplicity and the very high probability of correct operation, this may be the way to go (at least if you don't use JQuery).
T3] DOM-ready-- [however you get events: addEventListener("DOMContentLoaded"..., window.ondomcontentloaded=..., etc.] At this point the HTML has been completely parsed and JS is 100% available, including all functions that read or manipulate the HTML [getElementById(..., appendChild(..., etc.].
T4] Render-done-- The browser is finished displaying the content on the screen. There is NOT any such event or any reasonable cross-browser version-agnostic way to detect this situation. That's just as well, as you probably don't really want this anyway. If the browser has already displayed the page on the screen and then you manipulate the DOM, you'll get a "flash", where both the before and the after are visible on the screen at least briefly. What you probably really want is the point where you can execute arbitrary JS code; that's the previous (T3] DOM-ready) point in time.
Either attach a callback to window.onload
window.onload = function(){
// your code here
};
this will fire when all resources are loaded (which might be not what you want).
Or put all of your code at the bottom the page (before the closing body tag). The code will be run when the HTML is parsed.
FWIW, here is the jQuery code. You see, the use custom event handlers for IE and the other browsers, but use window.onload as fallback:
// 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();
}
}
As with a lot of JavaScript this will depend on which browser you are using.
As #Avitus' answer, have you looked at the execution point of JQuery's document ready event? This has been generalised across all browsers.
If you plan on using a javascript library (like jQuery) I would rather go with the $(document).ready() statement which is called once the DOM is ready to be manipulated.
The other option I see would be to include your function call at the end of your HTML page so that all the HTML content would be loaded so you can afterward execute your code safely
"The onload event waits for all binary content to download before firing. No kitty-tickilng until then."
As this post says, it is called after all binary content is downloaded, you need to listen for a ready event either using jQuery's ready, or your own function. This project looks interesting.
There are many cross browser implementations so use either jQuery or that project I linked to.
I have written my own function for my library, it uses internal methods so will not work on its own but might give you a feel for what you have to do. You can find that function here.
This is generally how I manage progressive enhancement whilst keep the experience clean, but how safe is it? is there potential for a race condition and this not working?
Imagine the simple abstract scenario, you want to display something differently if you have javascript support.. this is generally what I will end up doing:
<div id="test">original</div>
<script type="text/javascript">
var t = document.getElementById('test');
t.innerHTML = 'changed';
</script>
Many may claim you should use a framework and wait for a domready event, and do changes there.. however there is a significant delay where the 'test' element will have already been rendered before the end of the document and the css are ready and a domready triggers.. thus causing a noticable flicker of 'original'.
Is this code liable to race condition failures? or can I guarentee that an element is discoverable and modifiable if it exists before the script?
Thanks in advance.
You can, but there are issues surrounding doing it.
First off, in IE if you attempt to manipulate a node that has not been closed (e.g. BODY before its close tag which should be below your JS) then you can encounter IE's "OPERATION ABORTED" error which will result in a blank page. Manipulation of a node includes appending nodes, moving nodes, etc.
In other browsers the behavior is undefined, however they do usually behave as you would expect. The main issue is that as your page evolves, the page may load/parse/run differently. This may cause some script to run before a browser defines referenced elements have actually been created and made available for DOM manipulation.
If you are attempting to enhance your user perceived performance (i.e. snappiness). I highly suggest that you avoid this path and look into lightening your pages. You can use Yahoo's YSlow/Google's Page Performance Firebug to help you get started.
Google's Page Speed
Yahoo's YSlow
You can manipulate the DOM before it has fully loaded, but it can be risky. You obviously can't guarantee that the bit of the DOM you are trying to manipulate actually exists yet, so your code may fail intermittently.
As long as you only modify nodes which preceed the script block (ie the node's closing tag preceeds the script's opening tag), you shouldn't encounter any problems.
If you want to make sure the operation succeeds, wrap the code in a try...catch block and call it again via setTimeout() on failure.
In Viajeros.com I have a loading indicator working since 8-9 months and I have no problems so far. It looks like this:
<body>
<script type="text/javascript">
try {
document.write('<div id="cargando"><p>Cargando...<\/p><\/div>');
document.getElementById("cargando").style.display = "block";
} catch(E) {};
</script>
Accessing the DOM prematurely throws exceptions in IE 5 and Navigator 4.
I have a javascript function that manipulates the DOM when it is called (adds CSS classes, etc). This is invoked when the user changes some values in a form. When the document is first loading, I want to invoke this function to prepare the initial state (which is simpler in this case than setting up the DOM from the server side to the correct initial state).
Is it better to use window.onload to do this functionality or have a script block after the DOM elements I need to modify? For either case, why is it better?
For example:
function updateDOM(id) {
// updates the id element based on form state
}
should I invoke it via:
window.onload = function() { updateDOM("myElement"); };
or:
<div id="myElement">...</div>
<script language="javascript">
updateDOM("myElement");
</script>
The former seems to be the standard way to do it, but the latter seems to be just as good, perhaps better since it will update the element as soon as the script is hit, and as long as it is placed after the element, I don't see a problem with it.
Any thoughts? Is one version really better than the other?
The onload event is considered the proper way to do it, but if you don't mind using a javascript library, jQuery's $(document).ready() is even better.
$(document).ready(function(){
// manipulate the DOM all you want here
});
The advantages are:
Call $(document).ready() as many times as you want to register additional code to run - you can only set window.onload once.
$(document).ready() actions happen as soon as the DOM is complete - window.onload has to wait for images and such.
I hope I'm not becoming The Guy Who Suggests jQuery On Every JavaScript Question, but it really is great.
I've written lots of Javascript and window.onload is a terrible way to do it. It is brittle and waits until every asset of the page has loaded. So if one image takes forever or a resource doesn't timeout until 30 seconds, your code will not run before the user can see/manipulate the page.
Also, if another piece of Javascript decides to use window.onload = function() {}, your code will be blown away.
The proper way to run your code when the page is ready is wait for the element you need to change is ready/available. Many JS libraries have this as built-in functionality.
Check out:
http://docs.jquery.com/Events/ready#fn
http://developer.yahoo.com/yui/event/#onavailable
Definitely use onload. Keep your scripts separate from your page, or you'll go mad trying to disentangle them later.
Some JavaScript frameworks, such as mootools, give you access to a special event named "domready":
Contains the window Event 'domready', which will execute when the DOM has loaded. To ensure that DOM elements exist when the code attempting to access them is executed, they should be placed within the 'domready' event.
window.addEvent('domready', function() {
alert("The DOM is ready.");
});
window.onload on IE waits for the binary information to load also. It isn't a strict definition of "when the DOM is loaded". So there can be significant lag between when the page is perceived to be loaded and when your script gets fired. Because of this I would recommend looking into one of the plentiful JS frameworks (prototype/jQuery) to handle the heavy lifting for you.
#The Geek
I'm pretty sure that window.onload will be called again when a user hits the back button in IE, but doesn't get called again in Firefox. (Unless they changed it recently).
In Firefox, onload is called when the DOM has finished loading regardless of how you navigated to a page.
While I agree with the others about using window.onload if possible for clean code, I'm pretty sure that window.onload will be called again when a user hits the back button in IE, but doesn't get called again in Firefox. (Unless they changed it recently).
Edit: I could have that backwards.
In some cases, it's necessary to use inline script when you want your script to be evaluated when the user hits the back button from another page, back to your page.
Any corrections or additions to this answer are welcome... I'm not a javascript expert.
My take is the former becauase you can only have 1 window.onload function, while inline script blocks you have an n number.
onLoad because it is far easier to tell what code runs when the page loads up than having to read down through scads of html looking for script tags that might execute.