Skip to content
Advertisement

selecting element based on innertext javascript

    <div>div-1
        <span>div-1-span-1
            <div>div-1-span-1-div</div>
            <span>div-1-span-1-span</span>
        </span>

    </div>

I am trying to search this DOM. My search criteria is innerText, which is “div-1”. If that innerText is found, then I want to return the value as “div-1-span-1-div” and “div-1-span-1-span” which are again the innerText. How to achieve this using Javascript.

Advertisement

Answer

While I’m unsure of the logic behind the requirements I believe the following code seems to do what you ask:

// declaring a named function that takes two arguments:
// selector: String, a CSS selector to determine the elements you're trying to search,
// needle: String, a string of text that you're searching for to identify a given element:
const findElementByText = (selector, needle) => {

  // here we convert the iterable NodeList returned from document.querySelectorAll()
  // into an Array, using the Array.prototype.from() method:
  return Array.from(
    // we pass the 'selector' argument to document.querySelectorAll()
    // to find all matching elements within the document:
    document.querySelectorAll(selector)
    // we then filter the resulting Array, using Array.prototype.filter()
    // which retains, or discards, Array-elements based on truthy/falsey
    // results of assessments within:
  ).filter(
    // using the anonymous Arrow function, we retrieve the childNodes of
    // each found element-node returned from document.querySelectorAll(),
    // 'el' is a reference to the current element-node of the Array of
    // element-nodes over which we're iterating:
    (el) => {
      // here we declare a variable, converting the HTMLCollection returned
      // by Node.childNodes into an Array of nodes in order to use Array-
      // methods such as Array.prototype.some():
      let children = Array.from(el.childNodes);

      // we use Array.prototype.some() to test if some of the Array-elements
      // match the supplied tests; if so the method returns a Boolean true
      // otherwise, if no Array-element matches, it returns a Boolean false:
      return children.some(
        // here we use the anonymous Arrow function, and we check that some
        // of the childNodes (referenced as 'child' within the function body)
        // are of nodeType === 3 (a textNode) and that the childNode's nodeValue
        // once trimmed of leading/trailing whitespace is equal to the
        // supplied String:
        (child) => child.nodeType === 3 && child.nodeValue.trim() === needle
      );
      // here we use Array.prototype.map() to construct a new Array based on
      // the Array-elements retained by Array.prototype.filter():
    }).map(
    // again, using an anonymous Arrow function, passing a reference to
    // the current element-node into the function:
    // first we create an Array from the iterable HTMLCollection of the
    // current element-node's children:
    (el) => Array.from(
      el.children
      // we then use Array.prototype.map() to create a new Array
      // based on those childNodes:
    ).map(
      // here we create another Array from the children of the
      // previous child (since you seem to explicitly want the
      // child-elements of the <span> in your posted code:
      (child) => Array.from(child.children)
      // we then use Array.prototype.flat() to collapse the Array
      // to only one-dimension:
    ).flat()
    // and then again, we use Array.prototype.map() to map the
    // textContent of each child:
    .map(
      (child) => child.textContent.trim()
      // and finally we flatten the multidimensional Array:
    ).flat()
  ).flat();
};

console.log(findElementByText('div', 'div-1'));
*,
 ::before,
 ::after {
  box-sizing: border-box;
  font-size: 1rem;
  line-height: 1.5;
  margin: 0;
  padding: 0;
}

div,
span {
  border: 1px solid var(--indicator);
  display: block;
  width: 90%;
  margin: 0.2em auto;
}

div {
  --indicator: lime;
}

span {
  --indicator: lightblue;
}
<div>div-1
  <span>div-1-span-1
     <div>div-1-span-1-div</div>
     <span>div-1-span-1-span</span>
  </span>
</div>

References:

User contributions licensed under: CC BY-SA
9 People found this is helpful
Advertisement