skip to Main Content

I’m trying to find an element in a page that does not have id’s or classes. The only way is by certain specific text that it’s contained in the div. I Found this function but it selects all the parent nodes, not only the inner child. (for obvious reasons because all the nested divs contains that text). How can I modify the function to select ONLY the div who directly have the searched text and excluding the search in children nodes?

Thanks for the help!

function contains(selector, text) {
  var elements = document.querySelectorAll(selector);
  return Array.prototype.filter.call(elements, function(element){
    return RegExp(text).test(element.textContent);
  });
}

console.log(contains('div', 'CORRECT-TEXT'));
<div>othertext
  <div>othertext
    <div>othertext
      <div>othertext
         <div>othertext CORRECT-TEXT othertext</div>
      </div>othertext
    </div>othertext
  </div>othertext
</div>othertext

2

Answers


  1. You’ll have to traverse the Text Nodes this way:

    const walkTextNodes = (node, filter) => {
        const result = [];
        const execute = node => {
            let child = node.firstChild;
            while (child) {
                switch (child.nodeType) {
                    case Node.TEXT_NODE:
                      if (child.textContent.indexOf(filter) > -1 ){
                        result.push(child.parentNode);
                      }
                      break;
                    case Node.ELEMENT_NODE:
                        execute(child);
                        break;
                }
                child = child.nextSibling;
            }
        }
        if (node) {
            execute(node);
        }
        return result;
    }
    
    const elementsFound = walkTextNodes(rootElement, "CORRECT-TEXT");
    console.log( elementsFound[0] );
    

    Once you find a text node containing the text you’re looking for, check the parentElement and push it into the result array.

    The code needs some testing and depending on your use case, it might require some tweaks, e.g. to return the first element or all the elements found with the keyword, etc. but I thinks it’s a good start.

    Update: here’s a refactoring of the original contains function that produces the same result:

    function contains( selector, text ){
      const elements = document.querySelectorAll(selector);
      return Array.prototype.filter.call(elements, function(element){
        if (RegExp(text).test(element.firstChild.textContent)) {
          return element;      
        }
      });
    }
    console.log(contains('div', 'CORRECT-TEXT')[0]);
    

    Working Demo:

    const walkTextNodes = (node, filter) => {
        const result = [];
        const execute = node => {
            let child = node.firstChild;
            while (child) {
                switch (child.nodeType) {
                    case Node.TEXT_NODE:
                      if (child.textContent.indexOf(filter) > -1 ){
                        result.push(child.parentNode);
                      }
                      break;
                    case Node.ELEMENT_NODE:
                        execute(child);
                        break;
                }
                child = child.nextSibling;
            }
        }
        if (node) {
            execute(node);
        }
        return result;
    }
    
    const elementsFound = walkTextNodes(rootElement, "CORRECT-TEXT");
    console.log( elementsFound[0] );
    
    // Take 2
    function contains( selector, text ){
      const elements = document.querySelectorAll(selector);
      return Array.prototype.filter.call(elements, function(element){
        if (RegExp(text).test(element.firstChild.textContent)) {
          return element;      
        }
      });
    }
    console.log(contains('div', 'CORRECT-TEXT')[0]);
    <div id="rootElement">othertext
      <div>othertext
        <div>othertext
          <div>othertext
             <div>othertext CORRECT-TEXT othertext</div>
          </div>othertext
        </div>othertext
      </div>othertext
    </div>othertext
    Login or Signup to reply.
  2. A simpler and more functional approach, see if it helps in solving your problem

    function contains(selector, text) {
      var elements = document.querySelectorAll(selector);
      return Array.prototype.filter.call(elements, function(element){
        return Array.prototype.some.call(element.childNodes, function(node) {
          return node.nodeType === 3 && RegExp(text).test(node.textContent);
        });
      });
    }
    console.log(contains('div', 'CORRECT-TEXT'));
    <div>othertext
      <div>othertext
        <div>othertext
          <div>othertext
             <div>othertext CORRECT-TEXT othertext</div>
          </div>othertext
        </div>othertext
      </div>othertext
    </div>othertext
    Login or Signup to reply.
Please signup or login to give your own answer.
Back To Top
Search