Connecting Tech Pros Worldwide Forums | Help | Site Map

removeChild skips on odd nodes, why?

VK
Guest
 
Posts: n/a
#1: Feb 8 '07
I must be missing something very obvious, but my nightly head doesn't
work anymore.

Press "Insert" button to add <insnodes after each <br>.
Now press "Delete" - only even <insare being removed.
ins.length is reported properly, each <inshas "insert" class name.
What a...?

<html
Quote:
><head
><title>Demo</title
><meta http-equiv="Content-Type"
content="text/html; charset=iso-8859-1"
Quote:
><style>
..insert {
background-color: #FFFF00;
color: #FF0000;
text-decoration: none;
padding-left: 2px;
padding-right: 2px;
}
</style
Quote:
><script>
function ins() {
var br = document.body.getElementsByTagName('br');
var ms = document.createElement('ins');
ms.appendChild(document.createTextNode('Message')) ;
ms.className = 'insert';
for (var i=0; i<br.length; i++) {
br[i].parentNode.insertBefore(ms.cloneNode(true),
br[i].nextSibling);
}
}


function del() {
var ins = document.body.getElementsByTagName('ins');
for (var i=0; i<ins.length; i++) {
if (ins[i].className == 'insert') {
alert( ins[i].parentNode.removeChild(ins[i]) );
}
}
}
</script
Quote:
></head
Quote:
><body
Quote:
><p>Demo <brtext</p
Quote:
><p>Demo <brtext</p
Quote:
><p>Demo <brtext</p
Quote:
><p>Demo <brtext</p
Quote:
><p><button type="button" onclick="ins()">Insert</button>
<button type="button" onclick="del()">Delete</button></p
Quote:
></body
></html>

Elegie
Guest
 
Posts: n/a
#2: Feb 8 '07

re: removeChild skips on odd nodes, why?


VK wrote:

Hi VK,
Quote:
Press "Insert" button to add <insnodes after each <br>.
Now press "Delete" - only even <insare being removed.
The DOM tree is live, when removing some elements from it you have to
make sure that your iterator is updated as well.
Quote:
alert( ins[i].parentNode.removeChild(ins[i]) );
alert( ins[i].parentNode.removeChild(ins[i--]) );


Regards,
Elegie.
VK
Guest
 
Posts: n/a
#3: Feb 8 '07

re: removeChild skips on odd nodes, why?


alert( ins[i].parentNode.removeChild(ins[i]) );
Quote:
>
alert( ins[i].parentNode.removeChild(ins[i--]) );
Thanks for the hint, this brought the code to life:

<html
Quote:
><head
><title>Demo</title
><meta http-equiv="Content-Type"
content="text/html; charset=iso-8859-1"
Quote:
><style>
..insert {
background-color: #FFFF00;
color: #FF0000;
text-decoration: none;
padding-left: 2px;
padding-right: 2px;
}
</style
Quote:
><script>
function ins() {
var br = document.body.getElementsByTagName('br');
var ms = document.createElement('ins');
ms.appendChild(document.createTextNode('Message')) ;
ms.className = 'insert';
for (var i=0; i<br.length; i++) {
br[i].parentNode.insertBefore(ms.cloneNode(true),
br[i].nextSibling);
}
}


function del() {
var ins = document.body.getElementsByTagName('ins');
for (var i=ins.length-1; i>=0; i--) {
if (ins[i].className == 'insert') {
ins[i].parentNode.removeChild(ins[i]);
}
}
}
</script
Quote:
></head
Quote:
><body
Quote:
><p>Demo <brtext</p
Quote:
><p>Demo <brtext</p
Quote:
><p>Demo <brtext</p
Quote:
><p>Demo <brtext</p
Quote:
><p><button type="button" onclick="ins()">Insert</button>
<button type="button" onclick="del()">Delete</button></p
Quote:
></body
></html>
I'm still missing I'm affraid how switching iteration direction would
solve the problem - but it obviously did. Maybe I'll get some enlight
after a good sleep... :-)

Elegie
Guest
 
Posts: n/a
#4: Feb 8 '07

re: removeChild skips on odd nodes, why?


VK wrote:
Quote:
I'm still missing I'm affraid how switching iteration direction would
solve the problem - but it obviously did. Maybe I'll get some enlight
after a good sleep... :-)
Rest, sport and good meals are three of the key success factors that,
IMHO, help a person get through intense stress situations that tend to
last for many days. Cheers up, things will clear up :)

Consider what removeChild does: it removes one of the object you're
iterating on. Your index, which refers to this object, now points to the
next object. Then, your "for loop" continues and increases the index by
one *while it is already pointing to the next node*, resulting in
skipping the node it had been referring to after the removal.

Ex.:

Given the following nodes: [A] [b] [C] [D]
Given an ii index, with ii==1, i.e. points to [b]
Removing [b] gives: [A] [C] [D]
Your index still equal to 1, ii==1, means it now points to [C]
The "for" statement increases ii to ii==2, i.e. points to [D]
[C] has been skipped in the process.


HTH,
Elegie.

PS : BTW VK your code is not displayed correctly when you post, ">"
marks appear at the beginning of lines, making my newsreader think
you're quoting stuff.
RobG
Guest
 
Posts: n/a
#5: Feb 8 '07

re: removeChild skips on odd nodes, why?


On Feb 8, 9:47 pm, "VK" <schools_r...@yahoo.comwrote:
[...]
Quote:
function del() {
var ins = document.body.getElementsByTagName('ins');
for (var i=ins.length-1; i>=0; i--) {
if (ins[i].className == 'insert') {
ins[i].parentNode.removeChild(ins[i]);
}
}
You might find it easier to iterate backwards using a while loop:

var n, i = ins.length;
while (n = ins[--i]) {
if (n.className == 'insert') {
n.parentNode.removeChild(n);
}
}


If you don't like assignment inside the while test:

while ( i-- ) {
n = ins[i];
if ...
}

There are many ways to skin a cat...

[...]
Quote:
I'm still missing I'm affraid how switching iteration direction would
solve the problem - but it obviously did. Maybe I'll get some enlight
after a good sleep... :-)
The NodeList returned by getElementsByTagName is live. When you
remove ins[i] then the node that was ins[i+1] is now ins[i].
Incrementing the counter on then next loop skips that node to the one
that was ins[i+2].

When you work backwards (i.e. from highest to lowest index), inserting
or removing items at or beyond the current index list doesn't affect
iteration over all the original nodes.


--
Rob


VK
Guest
 
Posts: n/a
#6: Feb 8 '07

re: removeChild skips on odd nodes, why?


On Feb 8, 4:01 pm, "RobG" <r...@iinet.net.auwrote:
Quote:
You might find it easier to iterate backwards using a while loop:
>
var n, i = ins.length;
while (n = ins[--i]) {
if (n.className == 'insert') {
n.parentNode.removeChild(n);
}
}
Agreed.
Quote:
The NodeList returned by getElementsByTagName is live. When you
remove ins[i] then the node that was ins[i+1] is now ins[i].
Incrementing the counter on then next loop skips that node to the one
that was ins[i+2].
>
When you work backwards (i.e. from highest to lowest index), inserting
or removing items at or beyond the current index list doesn't affect
iteration over all the original nodes.
Thanks to everyone, now I am clear on it.

getElementsByName / getelementsByTagName returns NodeList object (also
called HTMLCollection in older docs). In my coding I wrongly assumed
that NodeList is a kind of stripped down Array - without Array methods
and ability to store proprietary data, only with ability to iterate
using positive integer index.

In fact NodeList is Vector data type, so it automatically "shrinks" on
element removal with corresponding index renumbering of remaining
elements.

This way the safe way to remove elements is by going from the top to
bottom: in this case there is no index shift of remaining elements.

What wonders me now: one cannot directly remove elements from
NodeList, and a statement like
elm[i].parentNode.removeChild(elm[i])
changes the current NodeList in an indirect way (as a reflection of
DOM Tree change).

Does it mean that NodeList collection re-retrieved over and over
before any involving operation?

VK
Guest
 
Posts: n/a
#7: Feb 8 '07

re: removeChild skips on odd nodes, why?


On Feb 8, 3:17 pm, Elegie <ele...@invalid.comwrote:
Quote:
Rest, sport and good meals are three of the key success factors that,
IMHO, help a person get through intense stress situations that tend to
last for many days. Cheers up, things will clear up :)
Thanks :-)
Quote:
PS : BTW VK your code is not displayed correctly when you post, ">"
marks appear at the beginning of lines, making my newsreader think
you're quoting stuff.
Yeah. Normally I shape up my code before "going on public" (Usenet
posting): type="", conventional pretty-print and stuff. Last night I
was too tired for that I guess. This is anti-phantom pretty-print my
authoring software makes. Gives about 10% time gain on client-side
parsing stage for Gecko engines - because it doesn't have to allocate
bogus text nodes for line breaks - and up to 40% for intensive tree
traversal scripting - because of using native DOM methods without
extra checks for phantom nodes. Once I compared the productivity
impact - since then I'm using just that.
But I promise do not confuse in the future news agents and news
readers :-)

Closed Thread


Similar JavaScript / Ajax / DHTML bytes