How to search for an element with querySelector filtering through innerText?

Asked

Viewed 258 times

0

I’d like to know how I can through querySelector (or any other function) to obtain one or more elements (<div>, <a>, <button>, ...), filtering through the content of innerText.

In the document below for example, I want to get any kind of element that has innerText the string "bola". How could I do this using Javascript?

/*
A função abaixo é um exemplo que deve retornar os seguintes elementos:
<h1> - Linha 1
<a> - Linha 3
<div> - Linha 7
<div> - Linha 10
<span> - Linha 14
*/

const results = getElementsByInnerText("bola");
<h1>bola</h1>
<div id="something0">
    <a href="some link" class="something2">bola</a>
    <a href="some link2" class="something2">carro</a>
    <div class="some class">
        <div class="some class2">
            <div id="some id">bola</div>
            <div>casa</div>
        </div>
        <div>bola</div>
        <div class="something2">avião</div>
    </div>
</div>
<span>bola</span>

3 answers

2


You can select all elements and then filter them by the attribute value innerText. Check out the following function:

const queryByInnerText = (text) => {
    return [...document.body.querySelectorAll('*')].filter(e => e.innerText === text);
}

0

That’s probably not a good idea...

If, in the future, it is determined that it is best for the business to use the word "ball" instead of "ball", and therefore the terms in the applications, the next developer, or yourself, you will find it strange that a simple exchange of a text causes a certain functionality to fail. Changes to other points that add "ball" to the content or dynamic text could cause bugs and need to be handled properly (which is usually not worth it)

Also, there is no native API to do what you want, and any solution created involves searching all elements of the DOM and then filtering, which can be costly depending on the situation

The ideal solution would be to change the element by adding a class or attribute to be used as a filter:

<!-- document.querySelector('.bola') -->
<h1 class="bola">bola</h1>

<!-- ou -->

<!-- document.querySelector('[tipo="bola"]') -->
<h1 tipo="bola">bola</h1>

But if it is analyzed, and the best solution is really to search for the content of the element, it follows a solution that tends to be a little better than looking at everything:

((window) => {
  window.Element.prototype.getElementsByContent = function(search) {
    console.log('searching in', this);
    if (this.children.length === 0)
      return this.innerText === search ? [this] : [];

    let elements = [];

    for (const child of this.children)
      if (child.innerHTML.indexOf(search) !== -1)
        elements = elements.concat(child.getElementsByContent(search))
      else
        console.log('skip searching in', child);

    return elements;
  };
})(this);

console.log(document.body.getElementsByContent('bola'));
<h1>bola</h1>
<div id="something0">
    <a href="some link" class="something2">bola</a>
    <a href="some link2" class="something2">carro</a>
    <div class="some class">
        <div class="some class2">
            <div id="some id">barco</div>
            <div>casa</div>
        </div>
        <div>bola</div>
        <div class="something2">avião</div>
    </div>
</div>
<span>bola</span>

In this solution, it is not simply sought at all, it is made a simple check if the DOM element has, anywhere, the text sought, which allows to skip certain blocks, as in <div class="some class">, Since it does not possess, it jumps all the elements below it. In this example, it does not make much difference, because it is small and few elements are skipped, however, in real situations can fail to make the unnecessary search in dozens of elements

Another important observation, the search is done through the base element, in the example, document.body, if you have control of where the elements are, you can use a lower element and better restrict the search, if you do it from document.getElementById('something0'), the first and last item shall not be checked (h1 and span)

But this is a simple solution, if the search text is actually a class or id or part of it, for example, <div class="bolacha"></div> the check whether it contains the string "ball" will return true, but the "ball" found is "cookie" besides being a class and not the content of the element

0

As @Jassriver said, but I made an example for you.

Positive his case comment helped!

const 

aTag = document.getElementById("id-elemento"),

searchText = "bola",

found = [];

for (let i = 0; i < aTag.length; i++) {

  if (aTag[i].textContent == searchText)
  
    found.push(aTag[i]);
  
}

console.log (found)
<select id="id-elemento" name="existingList">
  <option value="1">bola</option>
  <option value="2">pedra</option>
  <option value="3">bola</option>
</select>

Note: if you want me to explain each line tell me in the comment I edit.

Browser other questions tagged

You are not signed in. Login or sign up in order to post.