0

The script below is meant to find all html comments in the page (there are 4) and return them as one string. I ran the script below and received a "Too Much Recursion" error.

Have I created an infinite loop or did I do something else?

function findComment()
{ 
        var olElement = document.getElementById("everything");//this is the id for my body element
        var comments = new Array();

        if (olElement.nodeType == 8)
        {
            comments[comments.length] = olElement;
        } else if(olElement.childNodes.length>0)
            {
                for (var i = 0; i<olElement.childNodes.length; i++)
                {
                    comments = comments.concat(findComment(olElement.childNodes[i]));
                }
            }
        alert(comments);
}

//window.onload = countListItems;
//window.onload = countTagItems;
//window.onload = getElements;
window.onload = findComment;
EricMPastore
  • 339
  • 2
  • 7
  • Given that `findComment` doesn't return anything, and that it doesn't have any parameters, this won't work: `comments.concat(findComment(olElement.childNodes[i]))`. It would evaluate to `comments.concat(undefined)`. Your code has the ID hard-coded, rather than using the passed-in argument. – Tyler Roper Sep 04 '19 at 19:08
  • Your code always looks for the same id and then looks for it's children. Ad infinitum – Lee Taylor Sep 04 '19 at 19:08
  • https://stackoverflow.com/questions/16151813/is-there-a-dom-api-for-querying-comment-nodes – j08691 Sep 04 '19 at 19:11
  • Everytime you call `findComment` method from the for loop you begin searching from the `everything` node. The function should have arguments to start from the childnodes – dRoyson Sep 04 '19 at 19:12

3 Answers3

0

Move the olElements variable outside the function and pass in the element you want to search. The recursion you have is always starting with 'everything';

var comments = new Array();
function findComment(element)
{ 
        if (element.nodeType == 8)
        {
            comments[comments.length] = element;
        } else if(element.childNodes.length>0)
            {
                for (var i = 0; i<element.childNodes.length; i++)
                {
                    comments = comments.concat(findComment(element.childNodes[i]));
                }
            }
        return comments;
}

var olElement = document.getElementById("everything");//this is the id for my body element
alert(findComment(olElement));
franzke
  • 517
  • 1
  • 6
  • 18
0

This is a rough cut version of how you could do it with a recursion. It is not really elegant but will do the work:

function fico(el){
  if (el.nodeType==8) return [el.textContent.trim()]
  else return [...el.childNodes].map(fico);
}
console.log(fico(document.querySelector("#everything")).toString().replace(/,+/g,", "));
<body id="everything">
<div>something <!-- comment1 -->
 <div>with something inside
   <!-- comment2 -->
   <div>and something further<div>
   <span>inside
 <!-- comment3 --></span>
    it 
 </div>
 more regular text 
 <!-- comment4 --> and enough.
</div></body>

Depending on the html input the function will return an array of subarrays with further levels of subarrays. To flatten it I used the Array-method toString() and then replace() with a regular expression to throw out the multiple commas in the result. There is still a superfluous one at the beginning ;-)

And here is an alternative version that uses a global comments array like you used in your code:

var comments=[];
function fico(el){
  if (el.nodeType==8) comments.push(el.textContent.trim());
  else [...el.childNodes].forEach(fico);
}
fico(document.querySelector("#everything"));  // collect comments ...
console.log(comments.join(', '));             // ... and display them
<body id="everything">
<div>something <!-- comment1 -->
 <div>with something inside
   <!-- comment2 -->
   <div>and something further<div>
   <span>inside
 <!-- comment3 --></span>
    it 
 </div>
 more regular text 
 <!-- comment4 --> and enough.
</div></body>
Carsten Massmann
  • 26,510
  • 2
  • 22
  • 43
0

Update: I tried both methods above and received error that either "element" or "el" is null. So...progress. I've pulled together my full code and html and posted below:

    <!DOCTYPE html>
    <html>
        <head>
            <title>A Simple Page</title>
            <script>
                var comments = new Array();
                    function findComment(element)
                    { 

                            if (element.nodeType == 8)
                            {
                                comments[comments.length] = element;
                            } else if(element.childNodes.length>0)
                                {
                                    for (var i = 0; i<element.childNodes.length; i++)
                                    {
                                        comments = comments.concat(findComment(element.childNodes[i]));
                                    }
                                }
                            return comments;
                    }

//window.onload = countListItems;
//window.onload = countTagItems;
//window.onload = getElements;
var olElement = document.getElementById("everything");//this is the id for my body element
window.onload = alert(findComment(olElement));
            </script>
        </head>
        <body>
            <div id="everything">
            <h1>Things to Do</h1><!--this is a title-->
            <ol id="toDoList"><!--this is a list-->
                <li>Mow the lawn</li><!--this is a list item-->
                <li>Clean the windows</li>
                <li>Answer your email</li>
            </ol>
            <p id="toDoNotes">Make sure all these things are done so you can get some rest.</p>
            </div>
        </body>
    </html>
EricMPastore
  • 339
  • 2
  • 7