1

I was reading w3schools and found this example:

<body>

<p>Hello World!</p>
<p>The DOM is very useful!</p>
<p>This example demonstrates the <b>length</b> property.</p>

<script type="text/javascript">
x=document.getElementsByTagName("p");

document.write("------<br />");
for (i=0;i<x.length;i++)
  { 
  document.write(x[i].innerHTML);
  document.write("<br />");
  }
document.write("------");
</script>
</body>

which works just fine. Then I thought doing the same with jQuery with

  <head>
    <meta http-equiv="Content-Type" content="text/html; charset=UTF-8" />
    <title>Demo Page</title>

<script type="text/javascript" src="jquery.js"></script>
    <script type="text/javascript" src="code.js"></script>
  </head>

and then in the code.js file have

$(document).ready(function()          {

      x=document.getElementsByTagName("p");

        document.write("------<br />");
        for (i=0;i<x.length;i++)
          { 
          document.write(x[i].innerHTML);
          document.write("<br />");
          }
        document.write("------");

              });

But with the second example, using jQuery the page loads forever and never prints the p tags innerHTML values.

Why is this?

4
  • 5
    This is because your using W3Schools to learn from. W3Schools is a bad reference and full of broken code. Learn from the MDN Commented Jun 4, 2011 at 22:43
  • Thank you for the reference... but stil why isnt the above code working? Commented Jun 4, 2011 at 22:45
  • 5
    As a follow-up on what Raynos said, I'll provide this link since you'll eventually run into it anyway if you keep learning from w3schools: w3fools.com Commented Jun 4, 2011 at 22:45
  • 2
    Using document.getElementsByTagName with jQuery... brilliant. </sarcasm> Commented Jun 4, 2011 at 22:46

4 Answers 4

3

calls to document.write after document.ready rewrites the document. and single the return value of document.getElementsByTagName is a live list the list becomes empty.

So what actually happens is that the document contains.

<p>Hello World!</p>
<p>The DOM is very useful!</p>
<p>This example demonstrates the <b>length</b> property.</p>

When the document is ready you call x = document.getElementsByTagName("p"); and x contains an array of <p> elements. But this is a live list and reflects the live state of the document. So when <p> elements get removed the list gets updated automatically.

You then call document.write with "-----<br/>" and this empties the document and replaces it with that. So the variable x now contains 0 <p> elements becuase there are 0 in the document.

The for loop doesn't run because x.length === 0

As mentioned this is broken because W3Schools gives you broken code.

I highly recommend you learn from the MDN

Live Example

A better way to achieve this with jQuery would be :

$(document).ready(function() {

    var ps = $("p");
    var body = $(document.body);

    body.append("------" + "<br/">);
    ps.each(function() {
       body.append(this.innerHTML + "<br/>"); 
    }):
    body.append("------");

});

Live Example

Sign up to request clarification or add additional context in comments.

Comments

3

Don't use document.write after the DOM is loaded, as it is with jQuery's $(document).ready. In fact, don't use document.write with jQuery at all. Use DOM manipulation instead. For instance:

$(document).ready(function() {
    var x = $('p'),
        toAdd = '';

    x.each(function() {
        toAdd += this.innerHTML;
    });

    $(document.body).append(toAdd);
});

See $, each, append.

Basically, learn jQuery's paradigms and patterns, and use them. Don't expect to be able to drop jQuery syntax randomly into Javascript code. Moreover, don't listen to W3Schools.

3 Comments

You're missing a couple of paradigms yourself. $(this).html() is preferred over this.innerHTML, toAdd should be an array of strings which is added to and then collapsed when appending to the body. See here: pastie.org/2020158
@OJ html uses this.innerHTML internally. The jQuery constructor is completely unnecessary. You could argue the array point either way, but I'm not convinced I see any advantage in your approach compared to mine.
@lonesomedady @OJ Benchmark. I think array vs string is a matter of personal choice.
2

You should read about document.write from a proper resource:

Writing to a document that has already loaded without calling document.open() will automatically perform a document.open call. Once you have finished writing, it is recommended to call document.close(), to tell the browser to finish loading the page.

As you are running the jQuery code on the document.ready event, the document (the structure) is already loaded. That means document.open is called. Lets see what MDC says about it:

If a document exists in the target, this method clears it (see the example above).

That means all the existing content is removed. Hence your code cannot access the p elements as they don't exist anymore.

Why does it work without jQuery?

In the original code, the JavaScript is executed before the structure finished loading (as it is part of it itself). Therefore document.open is not called and the content is not cleared:

If the document.write() call is embedded directly in the HTML code, then it will not call document.open().


There is hardly ever a reason to use document.write. Use proper DOM manipulation methods instead if you want to modify the document. You can find a list of methods provided by jQuery here.

2 Comments

That's not exactly accurate. "If the document.write() call is embedded directly in the HTML code, then it will not call document.open()." This is in fact the case in the OP's code. The second part you quote is fine, of course.
@Matt: I'm actually referring to the jQuery code... I edited my answer, I hope it is a bit clearer now...
0

that's because every time jQuery writes in the document you made some new elements so all scripts in the $(document).ready(); should be done again another time
maybe the solution is to write in another element like a "div"

$(document).ready(function()          {
x=document.getElementsByTagName("p");
     $('div.myDiv').html("------<br/>");
     for (var i=0; i<x.length; i++)
     { 
        $('div.myDiv').html(x[i].innerHTML());
        $('div.myDiv').html("<br />");
     }
     $('div.myDiv').html("------");
 });    

in the body you should put a "div" with a class name like "myDiv"

Comments

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.