-4
<div class="header circle">this is the header</div>
<div class"header circle"> this is the header of circle</div>

how to get the second dom that div textContent contains 'circle'?

I do know want to get all of the doms and then for(){} to get it.

user666
  • 329
  • 1
  • 7
  • 22
  • Did https://stackoverflow.com/questions/3813294/how-to-get-element-by-innertext not help? – CBroe Jun 20 '23 at 09:40
  • no, please do not get all doms and then search.@CBroe but thank you for your answer – user666 Jun 20 '23 at 09:54
  • No one is forcing you to "get all doms" with any of these solutions presented there, you can easily limit the initial element selection further, _before_ the check for the text content starts. – CBroe Jun 20 '23 at 09:58
  • in your link it will get all dom that right? but if I want to find div with textContent=my-text I have to get all divs?@CBroe – user666 Jun 20 '23 at 13:53
  • 1
    _"in your link it will get all dom that right?"_ - no, of course not - that question _is_ specifically about selecting elements by text content. – CBroe Jun 20 '23 at 13:59
  • var aTags = document.getElementsByTagName("a"); this is the code, will not it get all the dom of ????? – user666 Jun 21 '23 at 00:41
  • @CBroe I am misunderstand of the code? – user666 Jun 21 '23 at 00:42
  • 1
    That will first of all select all `a` elements, before it checks their text content, yes. But as I said - you can limit the selection further/ make it something else, depending on what exactly you need. – CBroe Jun 21 '23 at 05:44
  • @CBroe I know what you means. but what I am wondering is that is there any solutions DO NOT need to select all elements you know virtual doms right? it will select all elements in the document. but I thought it is not necessary. in one page I may only have several bindings but I have to select all. it is not good. So I come to ask that can I only select the element that is binding to something(variable or function) – user666 Jun 21 '23 at 08:11
  • 1
    This is the first time you mention anything about "binding" or virtual DOMs here, so far your question was only tagged javascript and html. – CBroe Jun 21 '23 at 08:15
  • @CBroe sorry I think it part of the binding. and virtual doms in virtual doms it will get all elements but I do not want it. – user666 Jun 21 '23 at 09:33
  • @user666: whether it's dynamically updated content (e.g virtual DOM) or static DOM output: you can't find a needle - or more precisely all needles - in a haystack without searching the whole haystack. You can compare performance between different methods (e.g. hangvirus's xPath concept). Maybe you can add conditions to stop the search once a result was found. If you encounter significant performance hits due to huge DOM lengths – you might rather opt for something like split/paginated views. – herrstrietzel Jun 25 '23 at 02:15

4 Answers4

2

In the best of the approaches you will need to iterate through all the DOM elements to find the matching content. But I think in your case, you are trying to avoid loading up all the div elements.

You can use XPATH to fetch the matching elements. The document.evaluate API has a full support can be used with an XPATH expression to get the single node in your case.

const foundElement = document.evaluate('//*[contains(text(), "circle")]', document, null, XPathResult.ORDERED_NODE_SNAPSHOT_TYPE).snapshotItem(0);

console.log(foundElement);
<div class="header circle">this is the header</div>
<div class="header circle">this is the header of circle</div>
hangvirus
  • 148
  • 7
  • This approach might be the most performant. I wasn't aware `evaluate` /xPath is this fast (or well optimized) in JS – my upvote!. Albeit my [test codepen](https://codepen.io/herrstrietzel/pen/ExONvov) might be too simplistic @hangvirus approach is most certainly pretty performant. However, the "sturdy way" of looping through all elements isn't too expensive either. – herrstrietzel Jun 25 '23 at 01:42
1

You can select all html elements with class circle as:

const allDivWithClasscircle = [...document.querySelectorAll(".circle")];

then, filter out elements with textContext circle as:

const elementsWithCircleText = allDivWithClasscircle.filter((el) =>
  el.textContent.includes("circle")
);

const allDivWithClasscircle = [...document.querySelectorAll(".circle")];

const elementsWithCircleText = allDivWithClasscircle.filter((el) =>
  el.textContent.includes("circle")
);

console.log(elementsWithCircleText);
<div class="header circle">this is the header</div>
<div class="header circle">this is the header of circle</div>
DecPK
  • 24,537
  • 6
  • 26
  • 42
1

yes, but I do not want to get all doms first. only want to the the one.

In JavaScript, you usually need to retrieve all the elements that match certain criteria and then filter through them to find the specific element you are looking for. However, you can make the process more efficient by using query selectors more specifically and then filtering.

A functional approach can more concise and easier to reason about, which can lead to cleaner and more maintainable code.

const filteredElements = [...document.querySelectorAll('div.header.circle')]
.filter(div => div.textContent.includes('circle'))

console.log(filteredElements);
<div class="header circle">this is the header</div>
<div class="header circle">this is the header of circle</div>

In detail:

  1. document.querySelectorAll('div.header.circle') selects all div elements with the classes header and circle. This returns a NodeList.
    Retrieve div elements with both the classes header and circle should already narrow down the number of elements you need to loop through.
  2. [...document.querySelectorAll('div.header.circle')] creates an array from the NodeList.
  3. .filter(div => div.textContent.includes('circle')) filters the array to only include div elements whose textContent contains the word 'circle'.

This approach uses method chaining and is more concise compared to using a loop with conditionals. It is also more declarative, making it easier to understand what the code is doing. This might not work on older browser though.

It is important to understand that DOM querying and filtering are inherently procedural processes, meaning that there is no way to directly query for an element based on its textContent without some form of iteration. The goal is to make this process as efficient as possible by narrowing down the search criteria.

The functional approach does not eliminate the procedural nature of DOM querying and filtering, but it abstracts it.
When you use .filter(), for example, there is still a loop happening behind the scenes, but you do not have to write the loop yourself. Instead, you provide a function that defines the criteria for filtering, and .filter() takes care of the iteration.

Warning: in the HTML code you provided, the second div is missing an equals sign (=) in the class attribute. It should be class="header circle" instead of class"header circle". This typo could cause the code not to work as expected.


In one page, I may only have several bindings, but I have to select all. It is not good.
So I come to ask that can I only select the element that is binding to something (variable or function)

Again, there is no built-in way to directly select elements based on their text content in JavaScript. The DOM API does not provide a method for this, likely due to performance reasons. Searching the entire DOM for a text string could be a very slow operation on a large page.

However, if you are using a library or framework that supports virtual DOM, like React or Vue.js, you can manage this more efficiently. You can bind your elements to a state variable, and then update the state when you need to change the elements. This way, you are not directly manipulating the DOM, which is faster and more efficient.

Here is an example using React:

import React, { useState } from 'react';

function MyComponent() {
  const [headerText, setHeaderText] = useState('this is the header');

  return (
    <div className="header circle" onClick={() => setHeaderText('this is the header of circle')}>
      {headerText}
    </div>
  );
}

export default MyComponent;

In this example, the div's text content is bound to the headerText state variable. When the div is clicked, the setHeaderText function is called to update the state, which in turn updates the div's text content.

This approach allows you to manage your elements' text content more efficiently, without having to select and filter all elements in the DOM.
However, it does require using a library or framework that supports the virtual DOM and state management, like React or Vue.js.

VonC
  • 1,262,500
  • 529
  • 4,410
  • 5,250
  • thank you for your answer but I do not want to get all doms of the specific elements. if I want to I will not ask this question. – user666 Jun 21 '23 at 00:43
  • @user666 The all point of this answer is to explain you *have to* select a subset of doms (all the `div.header.circle`, so not *all* doms) before filtering them. – VonC Jun 21 '23 at 04:15
  • yes maybe you are right. but in your answer you know the textContent is in div – user666 Jun 21 '23 at 08:12
  • but what about in a? in
    we do not konw so actually I have to get all the doms
    – user666 Jun 21 '23 at 08:12
  • @user666 Your question is about div, not a, hence my proposal. – VonC Jun 21 '23 at 08:42
  • @user666 I have edited the answer to include a section on bindings. – VonC Jun 21 '23 at 08:52
  • I am not using React or vue.js I am creating a binding framework. so I will not use them.but as you said I have to select all the elements and get which is binded. – user666 Jun 21 '23 at 09:32
  • Let us [continue this discussion in chat](https://chat.stackoverflow.com/rooms/254173/discussion-between-vonc-and-user666). – VonC Jun 21 '23 at 10:07
0
const elements = Array.from(document.querySelectorAll("div")).filter(div => div.textContent.includes('circle'));

This will get you the element that has circle in their textContent.

Note: It will fetch all the elements that has "circle" in their textContent. So you can traverse through the array of element accordingly.

Hope it helps!