12

I've got a javascript function 'doAll', which is supposed to write all the text that was put between <p>, </p> tags. In my code it is used in two ways.

It works correctly when I just call it at the end of the page. However it should also be triggered out when click-button event occurs. For some reason it doesn't do what it is supposed to do this time. When one click on the button it just prints the inner html of the very first <p>...</p> html element.

My question is why it works differently in these two situations and what should I do to fix this problem.

<!DOCTYPE html>
<html>
    <head>
        <script>
            function returnList(x)
            {
                return document.getElementsByTagName(x);
            }

            function writeList(x)
            {
                var i = 0;

                while (x[i])
                {
                    document.write(x[i++].innerHTML + '<br/>');
                }
            }

            function doAll(x) 
            {
                writeList(returnList(x));
            }
        </script>
    </head>

    <body>
        <p>XXX</p>
        <p>YYY</p>
        <div style = 'background-color: gray;'>
            <p>YYY</p>
            <p>XXX</p>
        </div>

        <button type = 'button' onclick = "doAll('p')">
            Click me!
        </button>

        <script>
            document.write('<br/>');
            doAll('p');
        </script>
    </body>
</html>

Here is the 'output':
XXX
YYY
YYY
XXX

XXX
YYY
YYY
XXX

And here is what one can see after clicking the button:
XXX

5
  • Why does the first output consist of 8 lines although there are only 4 p-tags? that looks like the on click is run to early. Commented Jul 15, 2013 at 13:25
  • Remember: debugger + browser developer tools are always your friends. Commented Jul 15, 2013 at 13:44
  • @LarsEbert: nope, it's not because of the click button. Four additional lines of output are the consequence of six last lines of my code :D. As you can see 'doAll' function is triggered automatically by the <script>...</script> section on the bottom of the code. Commented Jul 15, 2013 at 20:39
  • 1
    Since my "answer" got deleted, for the right reasons, I'll post this as a comment. I stand my ground when saying that JavaScript isn't meant to be written in C-like style. ASI is one problem that can occur unexpectedly. If you want to validate the 'correctness' of your JavaScript code, run it through the JSLint.org validator. The better you score there, the less likely unexpected bugs will pop up. ASI Source: stackoverflow.com/questions/2846283/… JSLint: jslint.com Commented Jul 16, 2013 at 8:12
  • @Arninja: Thanks :D It was a useful post :) Commented Jul 16, 2013 at 20:34

3 Answers 3

14

The problem is that the page is already rendered, when you click your button. Triggering document.write() at this point will override the whole document. It writes the first element, because this is the only element that still exists, when you triggered your function. Any other element will simply not be there after document.write() executed for the first time.

Even your function itself will not be part of the document anymore. If you MUST work with document.write() or you just want to use it for testing reasons, you have to somehow "cache" your data and output it at once:

function writeList(x) {
    var i = 0, data = "";

    while (x[i]) {
        data += x[i++].innerHTML + '<br/>';
    }

    document.write(data);
}
Sign up to request clarification or add additional context in comments.

Comments

3

document.write is able to write content only to a document which is being currently loaded. Once loaded, it behaves a little bit differently - see https://developer.mozilla.org/en-US/docs/Web/API/document.write . Use special container element and innerHTML to write your desired output.

function writeList(list) {
    var i, result = "";
    for (i = 0; i < list.length; i++) {
        result += list[i].innerHTML + "<br />";
    }
    document.getElementById("myContainer").innerHTML = result;
}

http://jsfiddle.net/3yPAW/1/

1 Comment

There is actually no need for the if in your for loop. Just have result += list[i].innerHTML + "<br />";.
2

The other two answers explained why, I'll suggest you how to avoid this:

append your HTML to innerHTML of the body (or another element);

instead of

document.write(x[i++].innerHTML + '<br/>');

use

document.getElementsByTagName("body")[0].innerHTML += x[i++].innerHTML + '<br/>';

Demo: http://jsfiddle.net/MNCbx/

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.