How to get tag in html page, if I know what text tag contains. E.g.:
<a ...>SearchingText</a>
How to get tag in html page, if I know what text tag contains. E.g.:
<a ...>SearchingText</a>
You'll have to traverse by hand.
var aTags = document.getElementsByTagName("a");
var searchText = "SearchingText";
var found;
for (var i = 0; i < aTags.length; i++) {
if (aTags[i].textContent == searchText) {
found = aTags[i];
break;
}
}
// Use `found`.
i < il
? What is that doing? –
Lili You could use xpath to accomplish this
var xpath = "//a[text()='SearchingText']";
var matchingElement = document.evaluate(xpath, document, null, XPathResult.FIRST_ORDERED_NODE_TYPE, null).singleNodeValue;
You can also search of an element containing some text using this xpath:
var xpath = "//a[contains(text(),'Searching')]";
Document.evaluate()
isn't supposed in IE browser –
Massy null
as a result, if I am here at Stackoverflow and I execute in console: document.evaluate("a[text()='share']", document, null, XPathResult.FIRST_ORDERED_NODE_TYPE, null).singleNodeValue;
? Firefox 63. I see many 'share' links. –
Ezaria //
. –
Ezaria var xpath = "//a[text()='SearchingText']";
This is not working, but var xpath = "//a[contains(text(),'Searching')]";
this works. Be aware of the excaped character, such as \' \'. –
Wink //a[contains(text(),'needle')]
to be a safer option, because any hidden characters / whitespace around the needle will thwart the more explicit [text()='needle']
(which would return null
if there's a trailing space, for instance) –
Annual //a[contains(normalize-space(text())='SearchingText'])
. –
Aciniform js var matchingElementSet = document.evaluate(xpath, document, null, XPathResult.ORDERED_NODE_ITERATOR_TYPE, null); while(element = result.iterateNext()) { // do something with each element }
developer.mozilla.org/en-US/docs/Web/API/XPathResult/… –
Aciniform shadow-root
elements? –
Charron You'll have to traverse by hand.
var aTags = document.getElementsByTagName("a");
var searchText = "SearchingText";
var found;
for (var i = 0; i < aTags.length; i++) {
if (aTags[i].textContent == searchText) {
found = aTags[i];
break;
}
}
// Use `found`.
i < il
? What is that doing? –
Lili Using the most modern syntax available at the moment, it can be done very cleanly like this:
for (const a of document.querySelectorAll("a")) {
if (a.textContent.includes("your search term")) {
console.log(a.textContent)
}
}
Or with a separate filter:
[...document.querySelectorAll("a")]
.filter(a => a.textContent.includes("your search term"))
.forEach(a => console.log(a.textContent))
Naturally, legacy browsers won't handle this, but you can use a transpiler if legacy support is needed.
querySelectorAll
result into an array and then using filter on it like that is perfect vanilla syntax without using messy XPath. A lot easier to understand at first glance, and much more compatible with other things as well. Thanks for the help! –
Northward You can use jQuery :contains() Selector
var element = $( "a:contains('SearchingText')" );
Error: <![EX[["Tried to get element with id of \"%s\" but it is not present on the page","a:contains('SearchingText')"]]]> TAAL[1]
though I have elements with "SearchingText" in them. –
Drummond Functional approach. Returns array of all matched elements and trims spaces around while checking.
function getElementsByText(str, tag = 'a') {
return Array.prototype.slice.call(document.getElementsByTagName(tag)).filter(el => el.textContent.trim() === str.trim());
}
Usage
getElementsByText('Text here'); // second parameter is optional tag (default "a")
if you're looking through different tags i.e. span or button
getElementsByText('Text here', 'span');
getElementsByText('Text here', 'button');
The default value tag = 'a' will need Babel for old browsers
a
will contain str
- el
will be included into getElementsByText
result; which is wrong. –
Mews document
into a passed variable elm
so I could narrow down before calling func, and no reason I can't just pass document
, but I prefer it that way. Also removed the default tag = 'a'
. Great answer though! I love how you used the name convention of existing methods. –
Excavate function findByTextContent(needle, haystack, precise) {
// needle: String, the string to be found within the elements.
// haystack: String, a selector to be passed to document.querySelectorAll(),
// NodeList, Array - to be iterated over within the function:
// precise: Boolean, true - searches for that precise string, surrounded by
// word-breaks,
// false - searches for the string occurring anywhere
var elems;
// no haystack we quit here, to avoid having to search
// the entire document:
if (!haystack) {
return false;
}
// if haystack is a string, we pass it to document.querySelectorAll(),
// and turn the results into an Array:
else if ('string' == typeof haystack) {
elems = [].slice.call(document.querySelectorAll(haystack), 0);
}
// if haystack has a length property, we convert it to an Array
// (if it's already an array, this is pointless, but not harmful):
else if (haystack.length) {
elems = [].slice.call(haystack, 0);
}
// work out whether we're looking at innerText (IE), or textContent
// (in most other browsers)
var textProp = 'textContent' in document ? 'textContent' : 'innerText',
// creating a regex depending on whether we want a precise match, or not:
reg = precise === true ? new RegExp('\\b' + needle + '\\b') : new RegExp(needle),
// iterating over the elems array:
found = elems.filter(function(el) {
// returning the elements in which the text is, or includes,
// the needle to be found:
return reg.test(el[textProp]);
});
return found.length ? found : false;;
}
findByTextContent('link', document.querySelectorAll('li'), false).forEach(function(elem) {
elem.style.fontSize = '2em';
});
findByTextContent('link3', 'a').forEach(function(elem) {
elem.style.color = '#f90';
});
<ul>
<li><a href="#">link1</a>
</li>
<li><a href="#">link2</a>
</li>
<li><a href="#">link3</a>
</li>
<li><a href="#">link4</a>
</li>
<li><a href="#">link5</a>
</li>
</ul>
Of course, a somewhat simpler way still is:
var textProp = 'textContent' in document ? 'textContent' : 'innerText';
// directly converting the found 'a' elements into an Array,
// then iterating over that array with Array.prototype.forEach():
[].slice.call(document.querySelectorAll('a'), 0).forEach(function(aEl) {
// if the text of the aEl Node contains the text 'link1':
if (aEl[textProp].indexOf('link1') > -1) {
// we update its style:
aEl.style.fontSize = '2em';
aEl.style.color = '#f90';
}
});
<ul>
<li><a href="#">link1</a>
</li>
<li><a href="#">link2</a>
</li>
<li><a href="#">link3</a>
</li>
<li><a href="#">link4</a>
</li>
<li><a href="#">link5</a>
</li>
</ul>
References:
Simply pass your substring into the following line:
Outer HTML
document.documentElement.outerHTML.includes('substring')
Inner HTML
document.documentElement.innerHTML.includes('substring')
You can use these to search through the entire document and retrieve the elements that contain your search term:
function get_elements_by_inner(word) {
res = []
elems = [...document.getElementsByTagName('a')];
elems.forEach((elem) => {
if(elem.outerHTML.includes(word)) {
res.push(elem)
}
})
return(res)
}
Usage:
How many times is the user "T3rm1" mentioned on this page?
get_elements_by_inner("T3rm1").length
1
How many times is jQuery mentioned?
get_elements_by_inner("jQuery").length
3
Get all elements containing the word "Cybernetic":
get_elements_by_inner("Cybernetic")
To get the filter method from user1106925 working in <=IE11 if needed
You can replace the spread operator with:
[].slice.call(document.querySelectorAll("a"))
and the includes call with a.textContent.match("your search term")
which works pretty neatly:
[].slice.call(document.querySelectorAll("a"))
.filter(a => a.textContent.match("your search term"))
.forEach(a => console.log(a.textContent))
Array.from
instead of [].slice.call
. For example: Array.from(document.querySelectorAll('a'))
–
Capelin You can do this, not sure if this is recommended but it works for me.
[... document.querySelectorAll('a')].filter(el => el.textContent.includes('sometext'));
I found the use of the newer syntax a little bit shorter compared to the others answer. So here's my proposal:
const callback = element => element.innerHTML == 'My research'
const elements = Array.from(document.getElementsByTagName('a'))
// [a, a, a, ...]
const result = elements.filter(callback)
console.log(result)
// [a]
document.querySelectorAll('a').forEach(function (item) {
if (item.innerText == 'SearchingText') {
console.dir(item);
}
});
You can use a TreeWalker
to go over the DOM nodes, and locate all text nodes that contain the text, and return their parents:
const findNodeByContent = (text, root = document.body) => {
const treeWalker = document.createTreeWalker(root, NodeFilter.SHOW_TEXT);
const nodeList = [];
while (treeWalker.nextNode()) {
const node = treeWalker.currentNode;
if (node.nodeType === Node.TEXT_NODE && node.textContent.includes(text)) {
nodeList.push(node.parentNode);
}
};
return nodeList;
}
const result = findNodeByContent('SearchingText');
console.log(result);
<a ...>SearchingText</a>
While it's possible to get by the inner text, I think you are heading the wrong way. Is that inner string dynamically generated? If so, you can give the tag a class or -- better yet -- ID when the text goes in there. If it's static, then it's even easier.
This does the job.
Returns an array of nodes containing text
.
function get_nodes_containing_text(selector, text) {
const elements = [...document.querySelectorAll(selector)];
return elements.filter(
(element) =>
element.childNodes[0]
&& element.childNodes[0].nodeValue
&& RegExp(text, "u").test(element.childNodes[0].nodeValue.trim())
);
}
const el = Array.from(document.body.querySelectorAll('a')).find(elm => elm.textContent.toLowerCase().includes('searching text'));
const el2 = document.evaluate('//a[contains(text(), "text5")]', document, null, XPathResult.FIRST_ORDERED_NODE_TYPE, null).singleNodeValue;
console.log(el, el2);
<a href="#">text1</a>
<a href="#">text2</a>
<a href="#">Searching Text</a>
<a href="#">text3</a>
<a href="#">text4</a>
<a href="#">text5</a>
I think you'll need to be a bit more specific for us to help you.
If the text is unique (or really, if it's not, but you'd have to run through an array) you could run a regular expression to find it. Using PHP's preg_match() would work for that.
If you're using Javascript and can insert an ID attribute, then you can use getElementById('id'). You can then access the returned element's attributes through the DOM: https://developer.mozilla.org/en/DOM/element.1.
I've just needed a way to get the element that contains a specific text and this is what I came up with.
Use document.getElementsByInnerText()
to get multiple elements (multiple elements might have the same exact text), and use document.getElementByInnerText()
to get just one element (first match).
Also, you can localize the search by using an element (e.g. someElement.getElementByInnerText()
) instead of document
.
You might need to tweak it in order to make it cross-browser or satisfy your needs.
I think the code is self-explanatory, so I'll leave it as it is.
HTMLElement.prototype.getElementsByInnerText = function (text, escape) {
var nodes = this.querySelectorAll("*");
var matches = [];
for (var i = 0; i < nodes.length; i++) {
if (nodes[i].innerText == text) {
matches.push(nodes[i]);
}
}
if (escape) {
return matches;
}
var result = [];
for (var i = 0; i < matches.length; i++) {
var filter = matches[i].getElementsByInnerText(text, true);
if (filter.length == 0) {
result.push(matches[i]);
}
}
return result;
};
document.getElementsByInnerText = HTMLElement.prototype.getElementsByInnerText;
HTMLElement.prototype.getElementByInnerText = function (text) {
var result = this.getElementsByInnerText(text);
if (result.length == 0) return null;
return result[0];
}
document.getElementByInnerText = HTMLElement.prototype.getElementByInnerText;
console.log(document.getElementsByInnerText("Text1"));
console.log(document.getElementsByInnerText("Text2"));
console.log(document.getElementsByInnerText("Text4"));
console.log(document.getElementsByInnerText("Text6"));
console.log(document.getElementByInnerText("Text1"));
console.log(document.getElementByInnerText("Text2"));
console.log(document.getElementByInnerText("Text4"));
console.log(document.getElementByInnerText("Text6"));
<table>
<tr>
<td>Text1</td>
</tr>
<tr>
<td>Text2</td>
</tr>
<tr>
<td>
<a href="#">Text2</a>
</td>
</tr>
<tr>
<td>
<a href="#"><span>Text3</span></a>
</td>
</tr>
<tr>
<td>
<a href="#">Special <span>Text4</span></a>
</td>
</tr>
<tr>
<td>
Text5
<a href="#">Text6</a>
Text7
</td>
</tr>
</table>
© 2022 - 2024 — McMap. All rights reserved.