Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Cloned node isn't equal to original node (with isEqualNode)

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.

like image 747
Pikrass Avatar asked Dec 30 '12 15:12

Pikrass


2 Answers

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/

like image 107
Igor Zalutski Avatar answered Nov 04 '22 12:11

Igor Zalutski


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.

like image 32
Yann Sagon Avatar answered Nov 04 '22 13:11

Yann Sagon