Home > Software design >  AppendChild in for loop adds every second child?
AppendChild in for loop adds every second child?

Time:10-23

I need to wrap children element in wrap-of-parent. Before wraping add some attributes to parent and child elements. In the code described below, everything works well if the children are one below the other in a separate row, and if they are in one row, every other child is inserted into the wrap-of-parent. Why is this happening and how to fix it?

I get:

<div id="container">
<div id="parent1">
    <div id="child1"></div>
    <div id="child2"></div>
    <div id="wrap-of-parent1">
        <div id="child3"></div>
        <div id="child4"></div>
    </div>
</div>

I need to get:

<div id="container">
<div id="parent1">
    <div id="wrap-of-parent1">   
        <div id="child1"></div>
        <div id="child2"></div>
        <div id="child3"></div>
        <div id="child4"></div>
    </div>
</div>

Code:

   var container = document.getElementById("container");
   const parentDivs = container.querySelectorAll(":scope *"); //if child elements also have child elements, to wrap in
 
     for (let parent of parentDivs) {
     // create a new div
     let wrap = document.createElement('div');
     wrap.id = 'wrap-of-'   parent.id;
      // move the parent's children to it
     let children = parent.childNodes;
     
     for (let i = 0; i < children.length; i  ) {
     if (children[i].nodeType === Node.ELEMENT_NODE) {
         children[i].setAttribute("data", "somedata");
         wrap.append(children[i]);
     }}
     // and append it to the parent
         parent.appendChild(wrap);
     }
<div id="container">
    <div id="parent1">
        <div id="child1"></div><div id="child2"></div><div id="child3"></div><div id="child4"></div>
    </div>
</div>
<! - If the child elements are one below the other in a separate row it works, if they are in one row it does not work ->
<iframe name="sif1" sandbox="allow-forms allow-modals allow-scripts" frameborder="0"></iframe>

CodePudding user response:

If you keep moving the first (index 0) entry, it will work. You need to add an offset when the wrong nodeType is encountered to skip over those ones, and if there are no child nodes then don't process the node:

var container = document.getElementById("container");
const parentDivs = container.querySelectorAll(":scope *"); //if child elements also have child elements, to wrap in

for (let parent of parentDivs) {
    // create a new div
    if (parent.childNodes.length > 0) {
        let wrap = document.createElement('div');
        wrap.id = 'wrap-of-'   parent.id;
        // move the parent's children to it
        let children = parent.childNodes;
        
        const nChildren = children.length;
        let offset = 0;
    
        for (let i = 0; i < nChildren; i  ) {
            if (children[offset].nodeType === Node.ELEMENT_NODE) {
                children[offset].setAttribute("data", "somedata");
                wrap.append(children[offset]);
            } else {
                offset  ;
            }
        }
        // and append it to the parent
        parent.appendChild(wrap);
    }
}
<div id="container">
    <div id="parent1">
        <div id="child1"></div><div id="child2"></div><div id="child3"></div><div id="child4"></div>
    </div>
</div>
<iframe name="sif2" sandbox="allow-forms allow-modals allow-scripts" frameborder="0"></iframe>

  • Related