SoluableNonagon
SoluableNonagon

Reputation: 11755

Find an element with a class without library or getElementsByClassName

This is problem I was asked and am wondering how to do or whether it's a trick question. I've only been working with JavaScript for a short while, so I'm not too sure.

Assume you have a web page with lots of content. Without using any library or getElementsByClassName, traverse the DOM and find all elements which have a particular class name.

Sample HTML

<body>
    <div>
        <div class='myTarget'>
             Target exists here
        </div>
    </div>

    <div>
        <table>
            <tbody>
              <tr> <td class='myTarget'> Target exists here </td> </tr>
            </tbody>
        </table>
    </div>

    <div>
       <span class='myTarget notSameAsTarget'>Stuff<span>
    </div>

</body>

My first thought is that this should be a recursive function and should start at the root document.documentElement

JS:

var root = document.documentElement;
var targetClass = 'myTarget';
var elementsWithTargetClass = []; // store in array

function traverse(element, targetClassName){
    // get class of current element
    var currentClass = element.className;

    // add to array if class matches
    if(currentClass.trim() === targetClassName)
        elementsWithTargetClass.push(element);

    // recursive call
    if(element.children){
         traverse(element, targetClassName);
    }

}

Any suggestions on what I'm missing?

    // recursive call - updated
    if(element.children){
         for(var child in element.children)
             traverse(element.children[child], targetClassName);
    }

Upvotes: 2

Views: 1354

Answers (5)

Paul Roub
Paul Roub

Reputation: 36438

Taking into account elements with multiple classes, and starting with body:

  var targetClass = 'myTarget';
  var elementsWithTargetClass = []; // store in array
  var re = new RegExp("\\b" + targetClass + "\\b");
  
  traverse(document.body);
  
  for ( var j = 0; j < elementsWithTargetClass.length; ++j )
    elementsWithTargetClass[j].style.fontWeight = "bold";
  
  function traverse(element, targetClassName){
      // get class of current element
      var currentClass = element.className;
  
      if (currentClass.match(re))
      // add to array if class matches
    //  if(currentClass.trim() === targetClassName)
          elementsWithTargetClass.push(element);
  
      // recursive call
      if(element.children){
        for ( var i = 0; i < element.children.length; ++i )
           traverse(element.children[i]);
      }
  }
<div>
  <ul>
    <li class="myTarget">this</li>
    <li class="myTarget andAnotherClass">also this</li>
    <li>not this</li>
  </ul>
</div>

Upvotes: 2

Ryan
Ryan

Reputation: 14649

var root = document.documentElement;
var targetClass = 'myTarget';
var elementsWithTargetClass = []; // store in array
pre_order(root);

function pre_order(node) {
  if(node.className == targetClass) 
    elementsWithTargetClass.push(node);       
  for(var i=0; i < node.childNodes.length; i++)
    pre_order(node.childNodes[i]);
}
console.log(elementsWithTargetClass);

JSFiddle

Upvotes: 1

Scimonster
Scimonster

Reputation: 33409

Use document.querySelector. This is not getElementsByClassName(), nor a library. ;)

document.querySelector('.myTarget')

Upvotes: 2

Paul
Paul

Reputation: 646

Your recursive call to traverse() passes the same element that was initially passed in, so it's just doing the exact same thing over and over until the stack overflows (hey!). You need to call traverse for each of the children of element rather than passing element back in.

Upvotes: 8

k-nut
k-nut

Reputation: 3575

You are getting into to many recursions which makes the call stack grow to high. Try chaning your recursive function into a loop. This should not give you any problems.

Upvotes: 1

Related Questions