Hubert Siwkin
Hubert Siwkin

Reputation: 385

Javascript function works in unexpected way

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

Upvotes: 13

Views: 427

Answers (3)

Pavel Horal
Pavel Horal

Reputation: 18224

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/

Upvotes: 3

Amberlamps
Amberlamps

Reputation: 40498

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);
}

Upvotes: 14

Andrea Ligios
Andrea Ligios

Reputation: 50281

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/

Upvotes: 2

Related Questions