I'm managing a list of names in Javascript. When you check a box, your name appears in the list. When you uncheck it, it gets crossed out. And when you set the box to the indeterminate state, your name's removed.
I've got the name of the currently logged in user in a hidden div. The name is a span with style attributes.
I check if the name is already in the list with isEqualNode. When it's in the list when the page loads, it works fine: the name is found and so is updated when the box checked state change.
for(var i=0 ; i < bullet.childNodes.length ; i++) {
var node = bullet.childNodes[i];
if(node.className == 'crossed')
node = node.firstChild;
if(node.isEqualNode(document.getElementById('curUser').firstChild))
break;
}
// if i < bullet.childNodes.length, then we found the user's name in the list
When the name is not in the list, I clone the span.
var newName = document.getElementById('curUser').firstChild.cloneNode(true);
bullet.appendChild(newName);
This works, visually.
But I stumbled on something tricky: newName.isEqualNode(document.getElementById('curUser').firstChild)
is false! So if the box state change again, the newly added name won't be found and a new one will be created, again.
Here is what the span looks like:
<span style="font-weight: bold ; color: #003380 ;">Pikrass</span>
For the moment I'll just make the check less strict (I can just check the text data inside the span instead of relying on isEqualNode), but I'm interested in why a cloned node can be different than the original one, according to isEqualNode.
Relevant specs : cloneNode, isEqualNode
EDIT: I tested with Firefox and Chromium. With Firefox isEqualNode returns false, but with Chromium it returns true. Thanks Felix for pointing this out.
I'm managing a list of names in Javascript. When you check a box, your name appears in the list. When you uncheck it, it gets crossed out. And when you set the box to the indeterminate state, your name's removed.
I've got the name of the currently logged in user in a hidden div. The name is a span with style attributes.
I check if the name is already in the list with isEqualNode. When it's in the list when the page loads, it works fine: the name is found and so is updated when the box checked state change.
for(var i=0 ; i < bullet.childNodes.length ; i++) {
var node = bullet.childNodes[i];
if(node.className == 'crossed')
node = node.firstChild;
if(node.isEqualNode(document.getElementById('curUser').firstChild))
break;
}
// if i < bullet.childNodes.length, then we found the user's name in the list
When the name is not in the list, I clone the span.
var newName = document.getElementById('curUser').firstChild.cloneNode(true);
bullet.appendChild(newName);
This works, visually.
But I stumbled on something tricky: newName.isEqualNode(document.getElementById('curUser').firstChild)
is false! So if the box state change again, the newly added name won't be found and a new one will be created, again.
Here is what the span looks like:
<span style="font-weight: bold ; color: #003380 ;">Pikrass</span>
For the moment I'll just make the check less strict (I can just check the text data inside the span instead of relying on isEqualNode), but I'm interested in why a cloned node can be different than the original one, according to isEqualNode.
Relevant specs : cloneNode, isEqualNode
EDIT: I tested with Firefox and Chromium. With Firefox isEqualNode returns false, but with Chromium it returns true. Thanks Felix for pointing this out.
Share Improve this question edited Nov 19, 2014 at 21:18 Pik' asked Dec 30, 2012 at 15:58 Pik'Pik' 7,0971 gold badge31 silver badges25 bronze badges 11- 1 Which browser? It seems to work in Chrome: jsfiddle/WhxQP. – Felix Kling Commented Dec 30, 2012 at 16:29
- Interesting question. Here's a simplified example: jsfiddle/QtJJb – try-catch-finally Commented Dec 30, 2012 at 16:29
- This fiddle is not working in Firefox 17.x. – try-catch-finally Commented Dec 30, 2012 at 16:30
-
6
So, it seems that
.clone
does not copy the ID attribute, which would explain the differences. In your example though, thespan
element does not have an ID attribute. Does it in your actual code? – Felix Kling Commented Dec 30, 2012 at 16:38 - 1 @Felix Kling: I remend you to publish that as an answer. – try-catch-finally Commented Dec 30, 2012 at 16:41
3 Answers
Reset to default 4Just figured this out. According to specification, isEqualNode returns true only if both elements have equal amount of attributes. But if the source element has an ID, it is not copied since IDs shoud be unique, so it has less attributes. With class instead of ID it works fine.
Markup:
<div id="withId">withId content</div>
<div class="withoutId">withoutId content</div>
JS:
function test(node) {
var copy = node.clone(true);
document.body.appendChild(copy);
console.log('are equal: ' + copy.isEqualNode(node)
+ ', attributes lengths: ' + node.attributes.length + ' ' + copy.attributes.length
+ ', ids: ' + node.getAttribute('id') + ' ' + copy.getAttribute('id'));
}
test(document.getElementById('withId'));
// are equal: false, attributes lengths: 1 0, ids: withId null
test(document.getElementsByClassName('withoutId')[0]);
// are equal: true, attributes lengths: 1 1, ids: null null
http://jsfiddle/igorz/fxtDw/
It is written here Mozilla's reference (thanks @Bergi)
The duplicate node returned by cloneNode() receives a new uniqueID when it is added to another node
As you are doing an append, the id is probably changed at this moment.
Better late than never. :)
I can't reproduce the issue anymore with Firefox 17, so as discussed in ments this was probably a bug in Gecko, which has then been fixed.
I couldn't find any bug report however. I flag this answer as accepted for now, but if someone can find the bug report or an explanation of what was going on under the hoods I'll accept that instead.
Bergi's ments are right for the two other answers.