-1
    <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.

  • 2
    Could you please add more information. It is unclear what you exactly want? – snehal gugale May 03 '21 at 13:45
  • 1
    Based on the question title, have you looked at this question and its answers: https://stackoverflow.com/q/3813294/82548? Also, the explanation of your question is difficult to understand; do you want to select the "*div-1*" based on it's text? Which text? You want to "*get the value*" - what "value," a `
    ` element has no "value." So I'm assuming you want to get the text of its child elements? When attempting to solve your own problem how far did you get? What went wrong? In what way did it go wrong?
    – David Thomas May 03 '21 at 13:46
  • I hope the question is better clarified now. Your suggested article does not solve my scenario. – itchywinner May 03 '21 at 13:53
  • 1
    It's certainly a little better, sure; can I ask why the `textNode` of `div-1-span-1` is omitted from the returned `textNode` values? – David Thomas May 03 '21 at 14:06
  • Thanks. That is the scenario. The requirement is not to capture "div-1-span-1". – itchywinner May 03 '21 at 14:17
  • @itchywinner but that is against your requirement - *"My search criteria is innerText, which is "div-1""*. What is the criteria to exclude it? `div-1-span-1` includes `div-1`. Computers are really stupid you've to tell them exactly what to do – T J May 03 '21 at 15:18

1 Answers1

1

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:

David Thomas
  • 249,100
  • 51
  • 377
  • 410
  • Wow. Thanks it worked for my scenario. You have been helpful. @David says reinstate Monica – itchywinner May 04 '21 at 04:43
  • I’m glad to have been of help. If you feel this answer solved your problem, please consider accepting the answer (clicking on the check mark beside the text), it’s not obligatory to do so but is appreciated. – David Thomas May 04 '21 at 05:06