Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

How to find a DOM element by its text content?

I try to add new SVG elements to some nodes. For that purpose the nodes the elements are to be added to have to be found by a string contained in there text content, e.g. find any node which has "id0" inside the <text> tag.

Here is example of my HTML hierarchy:

<pre>
 <svg>
  <g>
   <g>
    <text> id3 </text>
    <text> 73% </text>
    <svg> ... </svg>
   </g>
   <g>
    <svg> ... </svg>
   </g>
   <g>
    <text> id0 </text>
    <text> 11% </text>
    <svg> ... </svg>
   </g>
   <g>
    <text> id1 </text>
    <text> 66% </text>
    <svg> ... </svg>
   </g>
   <g>
    <svg> ... </svg>
   </g>
  </g>
 </svg>
</pre>

I definitely don't know the right solution, but I think it is something like this:

d3.select('svg').select('g').selectAll('g').each(function (d, i) {})
                .select('g').select('text').filter(function () {
                  return (d3.select(this).text() === 'id0')
                })
                .select(function () {
                  return this.parentElement;
                })
                .append('svg')
                .attr('width', 400)
                .attr('height', 400)

If the tag <text> contains "id0", then return to the parent node and add an SVG element to it. But on the line return this.parentElement; an error occurs:

Property 'parentElement' does not exist on type 'Window'.

Similar errors occur when I use parentElement or parent.

like image 506
Ghosterus Avatar asked Sep 22 '19 19:09

Ghosterus


People also ask

How do I identify a DOM element?

The easiest way to find an HTML element in the DOM, is by using the element id.

What statement can be used to select the element from the DOM containing the text?

You can select an element based on its unique ID with the getElementById() method. This is the easiest way to find an HTML element in the DOM tree.


1 Answers

An alternative is xpath, which permits searching via text:

// if you know there's only one...
const singleResult = document.evaluate(`//*[name()="text" and contains(text(), "id0")]`, document, null, XPathResult.FIRST_ORDERED_NODE_TYPE, null).singleNodeValue;
console.log(singleResult.nodeName, singleResult.textContent)

// if there might be multiple results
const multipleResults = document.evaluate(`//*[name()="text" and contains(text(), "id_multiple")]`, document, null, XPathResult.ORDERED_NODE_SNAPSHOT_TYPE, null)

for (let i=0; i < multipleResults.snapshotLength; i++) {
  console.log(multipleResults.snapshotItem(i).nodeName, multipleResults.snapshotItem(i).textContent)
}
<svg>
    <g>
        <g>
            <text> id_multiple </text>
            <text> 73% </text>
            <svg></svg>
        </g>
        <g>
            <svg></svg>
        </g>
        <g>
            <text> id0 </text>
            <text> 11% </text>
            <svg></svg>
        </g>
        <g>
            <text> id_multiple </text>
            <text> 66% </text>
            <svg></svg>
        </g>
        <g>
            <svg></svg>
        </g>
    </g>
</svg>

The iterators (/snaphots) that are returned are unexpected for me - definitely have a read of this excellent answer: https://stackoverflow.com/a/32468320/2586761, and the docs: MDN: document.evaluate.

Note that because "common HTML nodes and svg nodes belong to different namespaces", you need to select SVG nodes like *[name()="svg"].

Regarding finding the text, I'd recommend using contains(text(),'needle') rather than the more explicit text()='needle' because any whitespace around needle would cause the selector to return null.

Interesting xpath vs CSS commentary: What is the difference between cssSelector & Xpath and which is better with respect to performance for cross browser testing?

Note that there's no IE support for document.evaluate

like image 108
ptim Avatar answered Sep 26 '22 16:09

ptim