How do I make this loop all children recursively?
Asked Answered
E

11

45

I have the following:

for (var i = 0; i < children.length; i++){
   if(hasClass(children[i], "lbExclude")){
       children[i].parentNode.removeChild(children[i]);
   }
};

I would like it to loop through all children's children, etc (not just the top level). I found this line, which seems to do that:

for(var m = n.firstChild; m != null; m = m.nextSibling) {

But I'm unclear on how I refer to the current child if I make that switch? I would no longer have i to clarify the index position of the child. Any suggestions?

Thanks!

Update:

I'm now using the following, according to answer suggestions. Is this the correct / most efficient way of doing so?

function removeTest(child) {
  if (hasClass(child, "lbExclude")) {
    child.parentNode.removeChild(child);
  }
}

function allDescendants(node) {
  for (var i = 0; i < node.childNodes.length; i++) {
    var child = node.childNodes[i];
    allDescendants(child);
    removeTest(child);
  }
}

var children = temp.childNodes;
for (var i = 0; i < children.length; i++) {
  allDescendants(children[i]);
};
Etna answered 26/4, 2010 at 8:53 Comment(4)
Do you know how many arrays you have nested here?Seychelles
Simply by the name m: m.parentNode.removeChild(m). There might be a problem, though, because removing a node and then taking its nextSibling (in the for clause) will not work as intended.Rightminded
@coshman, the amount of nested children will be variable.Etna
@dirk I didn't think of that. Do you have a proposed way of dealing with that problem?Etna
C
51

Normally you'd have a function that could be called recursively on all nodes. It really depends on what you want to do to the children. If you simply want to gather all descendants, then element.getElementsByTagName may be a better option.

var all = node.getElementsByTagName('*');

for (var i = -1, l = all.length; ++i < l;) {
    removeTest(all[i]);
}
Crocoite answered 26/4, 2010 at 9:9 Comment(2)
This will only get elements, not all nodes.Saltatorial
They are tested by a hasClass method however, so I believe they intend it to be elements.Renae
S
59
function allDescendants (node) {
    for (var i = 0; i < node.childNodes.length; i++) {
      var child = node.childNodes[i];
      allDescendants(child);
      doSomethingToNode(child);
    }
}

You loop over all the children, and for each element, you call the same function and have it loop over the children of that element.

Saltatorial answered 26/4, 2010 at 8:56 Comment(2)
Sorry, could you be more explicit about how to apply this function in my case?Etna
I think a more modern version of this would be function allDescendants (node) { node.childNodes.forEach(child => { allDescendants(child); doSomethingToNode(child); }); }Batty
C
51

Normally you'd have a function that could be called recursively on all nodes. It really depends on what you want to do to the children. If you simply want to gather all descendants, then element.getElementsByTagName may be a better option.

var all = node.getElementsByTagName('*');

for (var i = -1, l = all.length; ++i < l;) {
    removeTest(all[i]);
}
Crocoite answered 26/4, 2010 at 9:9 Comment(2)
This will only get elements, not all nodes.Saltatorial
They are tested by a hasClass method however, so I believe they intend it to be elements.Renae
B
4

There's no need for calling the 'allDescendants' method on all children, because the method itself already does that. So remove the last codeblock and I think that is a proper solution (á, not thé =])

            function removeTest(child){     
                if(hasClass(child, "lbExclude")){
                    child.parentNode.removeChild(child);
                }
            }

            function allDescendants (node) {
                for (var i = 0; i < node.childNodes.length; i++) {
                  var child = node.childNodes[i];
                  allDescendants(child);
                  removeTest(child);
                }
            }           

            var children = allDescendants(temp);
Becket answered 26/4, 2010 at 9:28 Comment(1)
The 'childNodes' it's was missing for me. Thanks a lot!Clarethaclaretta
C
3

You can use BFS to find all the elements.

function(element) {
    // [].slice.call() - HTMLCollection to Array
    var children = [].slice.call(element.children), found = 0;
    while (children.length > found) {
        children = children.concat([].slice.call(children[found].children));
        found++;
    }
    return children;
};

This function returns all the children's children of the element.

Chanticleer answered 2/2, 2017 at 10:28 Comment(0)
S
3

To get all descendants as an array, use this:

function getAllDescendants(node) {
    var all = [];
    getDescendants(node);

    function getDescendants(node) {
        for (var i = 0; i < node.childNodes.length; i++) {
            var child = node.childNodes[i];
            getDescendants(child);
            all.push(child);
        }
    }
    return all;
}
Streamliner answered 5/8, 2019 at 14:56 Comment(0)
F
2

The most clear-cut way to do it in modern browsers or with babel is this. Say you have an HTML node $node whose children you want to recurse over.

Array.prototype.forEach.call($node.querySelectorAll("*"), function(node) {
  doSomethingWith(node);
});

The querySelectorAll('*') on any DOM node would give you all the child nodes of the element in a NodeList. NodeList is an array-like object, so you can use the Array.prototype.forEach.call to iterate over this list, processing each child one-by-one within the callback.

Forecourse answered 31/5, 2018 at 11:56 Comment(2)
I'm sorry for my ignorance! But, '$node' requires something like JQuery? Is this solution valid for a 'vanilla' javascript code?Clarethaclaretta
No, $node is just a variable name holding an HTMLNode - don't get confused by the $ sign - any variable can have a $ in it.Forecourse
G
1

If you have jquery and you want to get all descendant elements you can use:

 var all_children= $(parent_element).find('*');

Just be aware that all_children is an HTML collection and not an array. They behave similarly when you're just looping, but collection doesn't have a lot of the useful Array.prototype methods you might otherwise enjoy.

Gilleod answered 8/6, 2015 at 20:24 Comment(0)
C
1

if items are being created in a loop you should leave a index via id="" data-name or some thing. You can then index them directly which will be faster for most functions such as (!-F). Works pretty well for 1024 bits x 100 items depending on what your doing.

if ( document.getElementById( cid ) ) {
 return;
} else {
  what you actually want
}

this will be faster in most cases once the items have already been loaded. only scrub the page on reload or secure domain transfers / logins / cors any else and your doing some thing twice.

Costate answered 15/12, 2018 at 13:51 Comment(0)
R
0

If you use a js library it's as simple as this:

$('.lbExclude').remove();

Otherwise if you want to acquire all elements under a node you can collect them all natively:

var nodes = node.getElementsByTagName('*');
for (var i = 0; i < nodes.length; i++) {
  var n = nodes[i];
  if (hasClass(n, 'lbExclude')) {
    node.parentNode.removeChild(node);
  }
}
Renae answered 26/4, 2010 at 9:35 Comment(1)
whoops, didn't see @J-P's answer.Renae
S
0
TreeNode node = tv.SelectedNode;
while (node.Parent != null)
{
    node = node.Parent;
}                    
CallRecursive(node);


private void CallRecursive(TreeNode treeNode)
{            
    foreach (TreeNode tn in treeNode.Nodes)
    {
        //Write whatever code here this function recursively loops through all nodes                 
        CallRecursive(tn);
    }
}
Switch answered 11/3, 2020 at 18:29 Comment(0)
C
0

The basic idea is remember that DOM is a tree structure. So, using the recursive approach, the idea is:

  1. Process parent obj;
  2. If obj has children(doesn't matter how many), iterate the children using childNodes function;
  3. Inside iteration, call the same function recursively passing the child object

Ex:

function doSomething(obj) {
   // Processing parent obj here
   if(obj.childNodes !== undefined && obj.childNodes !== null) {
       obj.childNodes.forEach((c) => {
           doSomething(c)
       })
   }
}

Note that the 'obj' parameter on doSomething inside the iteration is actually the 'child' object. Thus, you are processing the child node for each interation which means at the end of the loop and all recursive calls, this code will process all nodes in the tree starting from 'obj'.

I hope it helps!

Clarethaclaretta answered 1/4, 2023 at 18:40 Comment(0)

© 2022 - 2024 — McMap. All rights reserved.