Ornitier
Ornitier

Reputation: 171

Recursive function for going through unknown DOM

I am learning about js DOM and I want to make a recursive function that I could use to go through all nodes in any DOM. I made it, but I can not figure out why my first attempt is not working:

HTML

function mostrarNodosV2(node) {
  console.log(node.nodeName);
  if (node.firstElementChild != null) {
    node = node.firstElementChild;
    mostrarNodosV2(node);
  }

  if (node.nextElementSibling != null) {
    node = node.nextElementSibling;
    mostrarNodosV2(node);
  }

}

mostrarNodosV2(document);
<!DOCTYPE html>
<html>

<head>
  <meta charset="UTF-8">
  <title>Exercise IV</title>
</head>

<body>
  <h1> Just a header</h1>
  <p>Nice paragraph</p>
  <ul>
    <li>Im just an element list on an unordered list</li>
  </ul>
</body>

</html>

The flow is next:

  1. document node.
  2. we repeat the function with his first child: head node.
  3. we repeat the function with his first child: meta node.
  4. because of 'meta' has no childs, we repeat the function with his next sibling: title node.
  5. because of 'title' has no childs or next sibling, we end the function where node=title, we should end the function where node = meta, and we should continue checking the next sibling of head: body node.

Instead of that, if you debug or check the console you will see that browser repeats the section:

if (node.nextElementSibling != null) {
    node = node.nextElementSibling;
    mostrarNodosV2 (node);
}

Where node = meta, and so we get two 'TITLE' printed on console. Then it goes as it should have gone, and we get the 'body' node. The same problem happens with the 'LI' element.

So, I do not want another solution, I just did it, I just want to know why I go back to that 'if', because I don't get it.

If you debug it on developer tools it would be easier to understand.

Upvotes: 5

Views: 1363

Answers (3)

the8472
the8472

Reputation: 43150

There is no need to implement your own, the TreeWalker DOM Level 2 API allows traversal, choosing a custom start node and changing the direction.

Upvotes: 1

Patrick Roberts
Patrick Roberts

Reputation: 51977

The reason why your recursive function repeated nodes was because you reassigned node. Let's step through the function ourselves:

document -> has a child
  html -> has a child
    head -> has a child
      meta -> has no child, has a sibling
        title -> has no child or sibling
    head -> head has been overwritten with meta, which has a sibling
      title -> has no child or sibling
  html -> html has been overwritten with head, which has a sibling
    body -> has a child
      h1 -> has no child, has a sibling
        p -> has no child, has a sibling
          ul -> has a child
            li -> has no child or sibling
          ul -> ul has been overwritten with li, which has no sibling
    body -> body has been overwritten with h1, which has a sibling
      ...

So now you understand why it's bad to overwrite the function argument.

If you would like a more robust approach, here is how I would have written a recursive DOM traversal function:

function mostrarNodosV2(node) {
  if (node == null) {
    return;
  }

  console.log(node.nodeName);

  mostrarNodosV2(node.firstElementChild);
  mostrarNodosV2(node.nextElementSibling);
}

mostrarNodosV2(document);

The only difference here is I'm checking the node validity one recursion deeper than you were for each node, which reduces the verbosity of your approach.

Upvotes: 4

madox2
madox2

Reputation: 51931

you are re-assigning node variable, try this:

function mostrarNodosV2(node) {
    console.log(node.nodeName);
    if (node.firstElementChild != null) {
        var child = node.firstElementChild;
        mostrarNodosV2(child);
    }
    if (node.nextElementSibling != null) {
        var sibling = node.nextElementSibling;
        mostrarNodosV2(sibling);
    }
}
mostrarNodosV2(document);

Upvotes: 3

Related Questions