1

Secrets of the JavaScript Ninja shows how to remove and set an element's text:

HTML

<div id="test">Hey!
    <div id="child">delete me</div>
</div>

.

Javascript

var b = document.getElementById("test");

console.log("b before:", b);

while(b.firstChild) {
    console.log("removing child:",b.firstChild);
    b.removeChild(b.firstChild);
}

console.log("b's value post remove:", b);

b.appendChild(document.createTextNode("Some new text."));

var text = b.textContent || b.innerText;
console.log("text:", text);

Here's the console output:

b before: <div id=​"test">​Some new text.​</div>​
removing child:     "Hey!"
removing child:  <div id=​"child">​delete me​</div>​
removing child:  "  "
b's value post remove: <div id=​"test">​Some new text.​</div>​
text: Some new text. 

How could b equal Some new text.​ when the HTML is clearly set to Hey!?

Also, why would the b's value post remove: output show up as Some new text even though it hasn't been set yet?

http://jsfiddle.net/X6fYM/

Kevin Meredith
  • 41,036
  • 63
  • 209
  • 384
  • Using jQuery for such a job will surely make your life easier. To not set off insane rage on this site, I'll just recommend it, instead of giving an answer with it :P. Good luck! –  Dec 30 '13 at 22:28
  • You remove all nodes and then append a new textnode with that text, and now you're wondering why it has that text? It's because you added that text just before console logging it. – adeneo Dec 30 '13 at 22:30
  • 5
    @Allendar: There's no substitute for knowing what's actually going on, whether you use a library to make your life easier or not. – T.J. Crowder Dec 30 '13 at 22:32
  • @T.J.Crowder: Sadly that seems to be a minority view. – cookie monster Dec 30 '13 at 22:39

2 Answers2

5

If you're wondering why the console shows you something from later when you logged it before, it's because the console is (partially) a live display of what's in the DOM, not a bunch of strings written out at a moment in time. More about that in this question and its answers.

Basically, if you log an object, the console may treat that as a living display and update it if you change the object. If you log a string, the console will correctly display that as an unchanging thing. So:

var div = document.createElement("div");
console.log("div", div);
div.appendChild(document.createTextNode("foo"));

...can (subject to various conditions) show that the div contains foo, because the console updated the display when we changed it. (Live Example, open the console to see)

If you single-step through the code in a debugger, you can watch the console show one thing, then change it as we change its contents.

Community
  • 1
  • 1
T.J. Crowder
  • 1,031,962
  • 187
  • 1,923
  • 1,875
  • 2
    But he adds the node with some new text only after the logging?! – gdoron Dec 30 '13 at 22:32
  • 1
    @gdoron: Quite, it's the odd semi-liveness of the console. – T.J. Crowder Dec 30 '13 at 22:34
  • @T.J., my first point of misunderstanding is that, when calling `console.log("b before:", b);`, I should see `Hey!" since the JavaScript that modifies `b` hasn't yet been executed. Yet I see `Some new text`, which confuses me. – Kevin Meredith Dec 30 '13 at 22:36
  • @KevinMeredith: Yes, sorry, I misunderstood. I've updated the answer to address that: The console is *live* on most browsers (not like a terminal display or similar). So the display is updated when we change the object (subject to various conditions; for instance, Chrome does this with DOM elements but not with raw JavaScript objects containing simple string properties). – T.J. Crowder Dec 30 '13 at 22:39
  • 1
    @KevinMeredith: It can be helpful to log a serialization of data sometimes. It helps deal with the liveness that TJ describes. Use `b.outerHTML` for example. – cookie monster Dec 30 '13 at 22:45
0

Perhaps a little more explanation is in order.

Remember that each item in markup has some sort of element-context. Even text is a Node.

So, there are three Nodes inside of #test at the beginning of your script:

  1. Hey!
  2. <div id="child">delete me</div>
  3. [a blank text node]

This is why you see the output as the while statement works its way through #test's child nodes, removing each one in turn.

Having run your jsFiddle in Firefox, I'm not sure why you're seeing the output you posted:

b's value post remove: <div id=​"test">​Some new text.​</div>​

as it does not display that for me. It only displays that there is a div with the ID of test.

Also, in the beginning, you're creating a pointer to the test node, which is why, when you perform this call:

b.appendChild(document.createTextNode("Some new text."));

b suddenly has content... it never went away, you didn't dispose of the pointer to that object, and so when you test its contents, it displays the new text node that you just added to it.

Jason M. Batchelor
  • 2,951
  • 16
  • 25