0

(aggregated from another question)

Jquery 1.3.2 test code, run in FF3:

<input type="hidden" value="236434" id="ixd" name='ixd' />

<script>
console.log( $('#ixd').val() );

console.log( $('#ixd') );
console.log( $("input[name='ixd']") );
console.log( $("input:hidden") );

console.log( $("input[name='ixd'][type='hidden']") );
console.log( $("input[name='ixd']").val() );

$(document).ready(function() {
    console.log( $('#ixd').val() );
    console.log( $('#ixd') );
    console.log( $("input[name='ixd']") );
    console.log( $("input:hidden") );
});
</script>

Console output:

undefined
[]
[]
[]
[]
undefined
236434
[input#ixd 236434]
[input#ixd 236434]
[input#ixd 236434]

Can anybody offer any explanation or documentation links for hidden fields' data not being accessible until after $(document).ready()? It's not something I've ever experienced and it is proving troublesome.

Community
  • 1
  • 1
Andy
  • 17,423
  • 9
  • 52
  • 69
  • 1
    It almost sounds like you're asking, "Why isn't the document ready before it's ready?" – Joel Mueller Jun 15 '09 at 17:55
  • 1
    eh? Haven't you tried accessing a DOM element in script immediately after it's "declared"? Normally fine chuck. – Andy Jun 15 '09 at 18:25
  • I try to keep almost all of my scripts in external files so that they can be cached by the browser when the rest of my page content is dynamically generated. So no, I haven't tried accessing a DOM element from script prior to the dom-ready event, and I don't think it's a very good idea to do so. – Joel Mueller Jun 16 '09 at 19:08

5 Answers5

4

Well, I guess you answered your own question. Using document.getElementById() needs the DOM tree to be loaded by the browser in order for the DOM API (which includes getElementById) to work.

That means that you cannot be sure that any getElementById call will work properly until the $(document).ready function is called. Check out http://dean.edwards.name/weblog/2005/02/order-of-events/ for more

Flavius Stef
  • 13,740
  • 2
  • 26
  • 22
  • `getElementById()` should work for all elements preceding the script – Christoph Jun 15 '09 at 17:39
  • Why has this answer been modded up? It's incorrect and references a 4 year old article, probably for a different JS version. Christoph is correct - elements "declared" above the – Andy Jun 15 '09 at 18:28
  • @Andy: the referenced article (check it's follow-ups!) is still a nice read if you're interested in the so-called onload-problem (which has been solved well enough except in corner cases); it's just not really relevant in context of your problem ;) – Christoph Jun 15 '09 at 18:42
  • @Christoph I generally never use $(document).ready(), instead interspersing HTML with JS as it *seems* to reduce page load time (worth benchmarking!). Is this sensible? – Andy Jun 15 '09 at 18:52
  • @Andy: It might not reduce overall load times, but might result in better responsiveness; there are some nice articles about such things at yahoo and alistapart. Inline-scripting is often frowned upon as it breaks behavioral separation (a dogma of unobstrusive scripting); try to avoid the need for onload-actions altogether - event delegation and setting a single class on html or body if js is enabled can go a long way – Christoph Jun 15 '09 at 19:15
  • @Andy: Strictly speaking, you are right. But I think that getElementById() functioning before domReady is more of a tacit implementation choice by browser vendors and not something to rely upon (I failed to find any directive regarding its use in the W3C specs). – Flavius Stef Jun 15 '09 at 19:29
  • @Flavius: when `getElementById()` was introduced, there was no `DOMContentLoaded`, only `window.onload`, creating the so-called onload-problem; the solution was to put a script block as last element of `body` - meaning that strictly speaking, the DOM wasn't 'ready' when it executed - but this has worked reliably since the dawn of the DOM-era; also, the HTML5 spec makes heavy use of inline scripting and calling `getElementById()` without bothering with any ready checks, so even if it's not part of any standard (yet?), it's a de-facto standard – Christoph Jun 15 '09 at 20:13
4

Contrary to what others have written, your example should work as all major browsers allow access to elements which precede the executing script block. I don't have Firebug installed, but when replacing console.log() with document.writeln(), your example works as expected.

What happens when you create the following HTML document:

<script src="http://ajax.googleapis.com/ajax/libs/jquery/1.3.2/jquery.min.js"></script>
<input type="hidden" value="236434" id="ixd">
<pre><script type="text/javascript">
document.writeln($('#ixd').val());
document.writeln(document.getElementById('ixd').value);
</script></pre>
Christoph
  • 164,997
  • 36
  • 182
  • 240
  • Christoph, thanks for your answer and working example. When considered in context of miguelle's answer (adding and tags) it appears that firebug's console has a bug relating to either console.log or the parsing of hidden elements that aren't declared in valid HTML. – Andy Jun 15 '09 at 18:39
1

document.ready when page is "ready", meaning fully rendered. Your hidden field is probably not rendered on page yet at the moment in the start log.

Use ready() to start manipulating with page elements, not before that, "it's the only way to be sure" :)

Andrija
  • 14,037
  • 18
  • 60
  • 87
1

If I take your code (and add jQuery above) I get the same output. But if I change your code to the following, it will output the correct results. My guess is that firefox parses the HTML in a different order when no html/head/body is given.

<html>
<head>
<script type="text/javascript" src="jquery-1.3.2.js"></script>
</head>
<body>
<input type="hidden" value="236434" id="ixd" name='ixd' />

<script>
console.log( $('#ixd').val() );

console.log( $('#ixd') );
console.log( $("input[name='ixd']") );
console.log( $("input:hidden") );

console.log( $("input[name='ixd'][type='hidden']") );
console.log( $("input[name='ixd']").val() );

$(document).ready(function() {
    console.log( $('#ixd').val() );
    console.log( $('#ixd') );
    console.log( $("input[name='ixd']") );
    console.log( $("input:hidden") );
});
</script>

</body>
</html>

But, as said above, wait for the document to be ready before trying to retrieve elements by ID.

miguelle
  • 21
  • 1
  • Thanks miguelle, this is indeed correct! As speculated it appears that firebug's console has a bug relating to either console.log or the parsing of hidden elements that aren't declared in valid HTML. – Andy Jun 15 '09 at 18:40
0

You shouldn't trust anything until the dom is ready. It is just the way things work. Do you have a problem with waiting till ready?

Ballsacian1
  • 17,214
  • 2
  • 26
  • 25
  • Yes, i.e. an ajax call (to insert into/update a DOM "placeholder" element) fired before the DOM is finished loading – Andy Jun 15 '09 at 18:53