You can filter and reduce to get text nodes without child nodes:
[...$("#myelement").childNodes] .filter(node=>node.nodeType==3) .reduce((acc,node)=>acc+node.textContent.trim(), "")
Given the following HTML:
<html> <body> <div id="myelement"> First Text <span id="nestedelement">Extra Text</span> Last Text </div> </body> </html>
Let's break this down.
First, find your HTMLElement using a query selector:
/* css selector to find element by ID */ var locator = "#myelement" var element = document.querySelector(locator) /* or use the shorthand for querySelector */ element = $(locator) console.log("element", element) /* This include the extra text we don't want */ console.log("innerText", element.innerText)
Get children as a NodeList, and convert to an Array so we can iterate over it
var nodes = Array.from(element.childNodes) /* or use the "spread" operator */ nodes = [...element.childNodes]
Print the content of each text node by checking nodeType
for (node of nodes) { if (node.nodeType == 3) { var nodeText = node.textContent.trim() console.log("each node text: ", nodeText) } }
You can stop here if you want, since you can get everything you want from this. But let's look at using "functional" patterns to do the same thing.
Iterate using Array.forEach() and acccumulate the content of text nodes with a "closure" (fancy word for variable in outer scope)
var textNodes = [] nodes.forEach(node => { if (node.nodeType == 3) { /* TEXT_NODE == 3 */ textNodes.push(node.textContent.trim()) } }) console.log(textNodes.join("\n")) /* print a newline between text nodes */
Use Array.find() to get only the first text node
var firstNode = nodes.find(node => node.nodeType == Node.TEXT_NODE) console.log(firstNode.textContent.trim())
Use Array.findLast() to get only the last text node
var lastNode = nodes.findLast(node=> node.nodeType == Node.TEXT_NODE) console.log("lastNode: " + lastNode.textContent.trim())
Use Array.filter() to get all text nodes
var textNodes = nodes.filter(node => node.nodeType == Node.TEXT_NODE)
And then use Array.reduce() to combine the text nodes
var text = textNodes.reduce( (acc, textNode) => acc + textNode.textContent.trim(), "") /* start accumulator with an empty string */
Working snippet
/* find your HTMLElement */ var locator = "div#myelement" /* css selector to find element by ID*/ var element = document.querySelector(locator) /* or use shorthand for querySelector */ // element = $(locator) console.log("element: ", element) console.log("innerText: ", element.innerText) /* this includes the extra text we don't want */ /* get children as NodeList, and convert to Array so we can iterate over it */ var nodes = Array.from(element.childNodes) /* or use the "spread" operator */ nodes = [...element.childNodes] /* print each text node by checking nodeType */ for (node of nodes) { if (node.nodeType == 3) { console.log("each text node: ", node.textContent.trim()) /* remove extra whitespace including tabs and nelines */ } } /* you can stop here if you want, since you can have everything you want */ /* but let's look at using "functional" patterns to do the same thing */ /* accumulate content of text nodes with a "closure" (fancy word for variable in outer scope) */ var textNodes = [] nodes.forEach(node => { if (node.nodeType == Node.TEXT_NODE) { /* TEXT_NODE == 3 */ textNodes.push(node.textContent.trim()) } }) console.log("combined textNodes:", textNodes.join("\n")) /* print a newline between text nodes */ /* use Array.find() to get the first text node */ var firstNode = nodes.find(node => node.nodeType == Node.TEXT_NODE) console.log("firstNode: ", firstNode.textContent.trim()) /* use Array.findLast() to get the last text node */ var lastNode = nodes.findLast(node=> node.nodeType == Node.TEXT_NODE) console.log("lastNode: ", lastNode.textContent.trim()) /* use Array.filter() to get all text nodes */ var textNodes = nodes.filter(node => node.nodeType == Node.TEXT_NODE) /* use Array.reduce() to combine the text nodes */ combinedText = textNodes.reduce( (acc, textNode) => acc + textNode.textContent.trim(), "") /* start with an empty string */ console.log("combined text: ", combinedText)
<html> <body> <div id="myelement"> First Text <span id="nestedelement">Extra Text</span> Last Text </div> </body> </html>
console.log("combined text: ", text)
elementdoes not conain any content when.textContentandinnerTextare empty.