While writing some svg code I came across somthing that surprised me.
In let children = node.children
the variable children - seems to act as a pointer to the node's childrens list and not a variable that stores the list of children at the time it was defined. After looking into this it also seems to happen with regular HTML elements.
Is this logical behaviour or is it a bug ?
The following example shows this in detail:
<!DOCTYPE html>
<html>
<head>
<meta charset="utf-8">
<title>SVG Children Bug ?</title>
</head>
<body>
<svg id="mainGrid">
<circle cx="100" cy="75" r="60" stroke="black" stroke-width="3" fill="red" />
<path id="path"
d="m70,52 v48 h36 a24,24 0 0 0 0,-48 z m0,16 h-20 m0,16 h20 m60,-8 h20"
stroke="black"
fill="white"/>
<line x1="0" y1="0" x2="200" y2="150" style="stroke:rgb(255,0,0);stroke-width:2"
</svg>
<div id="mainDiv">
<div></div>
</div>
<script type="text/javascript">
// Svg check children
let svg = document.getElementById('mainGrid');
let Shildren = svg.children;
console.log( "Svg children len: ", Shildren.length ); // Should be 3
let newGroup = document.createElementNS('http://www.w3.org/2000/svg','g');
newGroup.setAttribute('class','newNode');
svg.appendChild( newGroup );
console.log( "Svg children len after adding: ", Shildren.length ); // Should be 3 not 4
// Div check children
let div = document.getElementById('mainDiv');
let Dhildren = div.children;
console.log( "Svg children len: ", Dhildren.length ); // Should be 1
let newDiv = document.createElement('div');
newDiv.setAttribute('class','newDiv');
div.appendChild( newDiv );
console.log("Div children len after adding: ", Dhildren.length ); // Should be 1 not 2
</script>
</body>
</html>
Is there a simple way to get the list of children at a specific time - or do I have to copy them one by one at the relevant moment?
As MDN says:
The ParentNode property children is a read-only property that returns a live HTMLCollection which contains all of the child elements of the node upon which it was called.
It's live, which means it can change as children are added or removed from it, which is not so intuitive and can be hard to deal with. An easy method would be to convert the children to an array any time the live part is an issue, to ensure that what you have is static:
let Shildren = [...svg.children];
// Svg check children
let svg = document.getElementById('mainGrid');
let Shildren = [...svg.children];
console.log("Svg children len: ", Shildren.length); // Should be 3
let newGroup = document.createElementNS('http://www.w3.org/2000/svg', 'g');
newGroup.setAttribute('class', 'newNode');
svg.appendChild(newGroup);
console.log("Svg children len after adding: ", Shildren.length); // Should be 3 not 4
// Div check children
let div = document.getElementById('mainDiv');
let Dhildren = [...div.children];
console.log("Svg children len: ", Dhildren.length); // Should be 1
let newDiv = document.createElement('div');
newDiv.setAttribute('class', 'newDiv');
div.appendChild(newDiv);
console.log("Div children len after adding: ", Dhildren.length); // Should be 1 not 2
<svg id="mainGrid">
<circle cx="100" cy="75" r="60" stroke="black" stroke-width="3" fill="red" />
<path id="path"
d="m70,52 v48 h36 a24,24 0 0 0 0,-48 z m0,16 h-20 m0,16 h20 m60,-8 h20"
stroke="black"
fill="white"/>
<line x1="0" y1="0" x2="200" y2="150" style="stroke:rgb(255,0,0);stroke-width:2"
</svg>
<div id="mainDiv">
<div></div>
</div>