Reputation: 7087
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.
Upvotes: 11
Views: 2448
Reputation: 7087
Better late than never. :)
I can't reproduce the issue anymore with Firefox 17, so as discussed in comments 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 comments are right for the two other answers.
Upvotes: 1
Reputation: 577
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.
Upvotes: 2
Reputation: 160
Just 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.net/igorz/fxtDw/
Upvotes: 4