<div class="classDiv">
<span id="mySpan"> TEXT 1 </span> TEXT 2
</div>
Using document.querySelectorAll(".classDiv")[0].textContent
Returns = TEXT 1 TEXT 2
How can i get only TEXT 2?
I tried with :not(span) without success.
Thanks
There’s nothing built-in that I’m aware of, but you can add a function to extract text nodes that are direct children of an element:
function getDirectText(node) {
var text = '';
for (var i = 0; i < node.childNodes.length; i++) {
var child = node.childNodes[i];
if (child.nodeType === 3) { // Node.TEXT_NODE
text += child.nodeValue;
}
}
return text;
}
and then:
var text = getText(document.getElementsByClassName('classDiv')[0]);
You might want to trim the result of whitespace, too.
Related
Suppose I have a sentence in the webpage DOM that when I examine it, consists of 3 text nodes followed by perhaps some element like BOLD or ITALIC. I want to merge the text nodes into one text node, since having adjacent text nodes is meaningless - there is no reason to have them. Is there a way to merge them easily?
Thanks
It seems that Node.normalize() is doing exactly what you want.
You can refer to: Node.normalize()
Maybe this will help you:
var parentNode = document.getElementById('pelements');
var textNode = document.createElement('p');
while (parentNode.firstChild) {
textNode.textContent += parentNode.firstChild.textContent;
parentNode.removeChild(parentNode.firstChild);
}
parentNode.appendChild(textNode);
<div id="pelements">
<p>A</p>
<p>B</p>
<p>C</p>
</div>
It is possible, but you need to specify the parent element. It should be possible to traverse the whole DOM and every node, but if you can avoid that, it would be better.
nodes = document.body.childNodes;
nodesToDelete = [];
function combineTextNodes(node, prevText) {
if (node.nextSibling && node.nextSibling.nodeType == 3) {
nodesToDelete.push(node.nextSibling);
return combineTextNodes(node.nextSibling, prevText + node.nodeValue);
} else {
return prevText + node.nodeValue;
}
}
for (i = 0; i < nodes.length; i++) {
if (nodes[i].nodeType == 3) {
nodes[i].nodeValue = combineTextNodes(nodes[i], '');
}
}
for (i = 0; i < nodesToDelete.length; i++) {
console.log(nodesToDelete[i]);
nodesToDelete[i].remove();
}
I'm trying to build a code that will search through an entire page for a specific word and if it finds this word, it is supposed to change the dom of the found element.
With my current code I'm able to find the element but when I change the innerHTML, it is changing all the page content.
How can I only change the innerHTML of the elements with the word JavaScript?
var nodes = document.querySelectorAll('*');
for (var i = 0; i < nodes.length; i++) {
if(nodes[i].innerHTML.indexOf('JavaScript') !== -1) {
console.log(typeof nodes[i]);
nodes[i].innerHTML = 'text changed';
}
}
I know that the problem is because I'm targetting all the nodes, and for this reason, it is changing all the HTML. How can I prevent that and only change elements that matches JavaScript?
hi when you use nodes[i].innerHTML.indexOf('JavaScript') this your <body> and <html> has this word in innerHTML then change your document but i add new condition to if like this nodes[i].innerHTML.indexOf('<') == -1 that say only in child node find this string and in parent node don't check
var nodes = document.querySelectorAll('*');
for (var i = 0; i < nodes.length; i++) {
console.log(nodes[i].innerHTML.indexOf('<'))
if(nodes[i].innerHTML.indexOf('JavaScript') != -1 && nodes[i].innerHTML.indexOf('<') == -1 ) {
console.log(typeof nodes[i]);
nodes[i].innerHTML = 'text changed';
}
}
<div>
<p>hello <span>JavaScript</span></p>
<h1>hello World!</h1>
</div>
I am learning javascript and I am stuck on a problem.
I need to get the text which comes directly from the div.
Example :
<div id ="parent_div">
<label>text1</label>
text2
</div>
in above HTML I need to get text2 which come directly under the div, but I don't want text1 in output.
So far I have tried
document.getElementById("parent_div").textContent
and
document.getElementById("parent_div").innerText
but I got both text1 and text2.
Please help me to get text2 only.
text1 will always appear, unless you hide it.
To get the sibling text, use:
document.getElementById("parent_div").childNodes[2].textContent;
Check the childNodes property to see where I get the number 2.
You could remove all the texts from the other elements:
var ele = document.getElementById("parent_div");
var text = ele.innerText;
for (var i = 0; i < ele.children.length; i++) {
text = text.replace(ele.children[i].innerText, "");
}
console.log(text);
<div id="parent_div">
<label>text1</label> text2
</div>
Filter by nodeType, you can get all the children from the element, then you can filter by what you need, you're looking for the nodeType 3 that represent all the text elements inside the div, the label is just ignored because is nodeType 1, you can learn more about this here in the documentation, there's my example working. I filtered all the next line texts, to give you only the one that you need.
let el = document.getElementById("parent_div"),
child = el.firstChild,
texts = [];
while (child) {
if (child.nodeType == 3) {
texts.push(child.data);
}
child = child.nextSibling;
}
const text = texts.join("").replace(/\n/ig, '');
console.log(text);
<div id="parent_div">
<label>text1</label>
text2
</div>
Here you can now by more specific with what want you want
You can try following (covers scenarios where there can be multiple text nodes scattered around many child nodes)
var response = ""; // result
document.getElementById("parent_div").childNodes.forEach(function(node){
if (node.nodeType === Node.TEXT_NODE) { // check for text nodes
response += node.textContent.trim(); // adding text nodes
}
});
console.log(response); // trim to get rid of leading and trailing spaces
<div id ="parent_div">
<label>text1</label>
text2
</div>
you could do it like this
var cloned = document.getElementById('parent_div').cloneNode(true);
Array.from(cloned.children).forEach(function(child) {
cloned.removeChild(child);
})
var text2 = cloned.innerText;
<div id ="parent_div">
<label>text1</label>
text2
</div>
I'd like to use jquery in such cases. Just because it makes life easy for me :)
And this is the way you can do that
var allOfThat = $("#parent_div")
.contents()
.filter(function () {
return this.nodeType === 3 && this.nodeValue.trim() !== "";
})[0].nodeValue;
console.log(allOfThat)
<script src="https://ajax.googleapis.com/ajax/libs/jquery/1.9.1/jquery.min.js"></script>
<div id ="parent_div">
<label>text1</label>
text2
</div>
I have a javascript variable like this:
var text = "A <mark id='1'>businessman</mark> should be able to <mark id='1'>manage</mark> his business matters";
I want to wrap each word in a span element with a different id but leave the words which are already wrapped in the <mark> tags. Like this:
text = "<span id='1'>A </span><mark id='1'>businessman</mark><span id='2'>should</span><span id='3'>be </span><span id='4'>able </span><span id='5'>to </span><mark id='2'>manage</mark><span id='6'>his </span><span id='7'>business </span><span id='8'>matters</span>";
I want all this in javascript or jquery but couldn't get it. It would be nice if you people can help me.
Thank you.
Try this,
function removeEmptyStrings(k) {
return k !== '';
}
function getWordsArray(div) {
var rWordBoundary = /[\s\n\t]+/; // split by tab, newline, spaces
var output = [];
for (var i = 0; i < div.childNodes.length; ++i) { // Iterate through all nodes
var node = div.childNodes[i];
if (node.nodeType === Node.TEXT_NODE) { // The child is a text node
var words = node.nodeValue.split(rWordBoundary).filter(removeEmptyStrings); // check for emptyness
for (var j = 0, l = words.length; j < l; j++) {
// adding class txtSpan so that it will not affect your spans already available in your input.
output.push('<span class="txtSpan">' + words[j] + '</span>');
}
} else { // add directly if not a text node
output.push(node.outerHTML);
}
}
return output;
}
var counter = 1,
html = getWordsArray($('#editor')[0]).join('');
$('#output').html(html).find('span.txtSpan').each(function() {
this.id = 'span-' + counter++;
});
span.txtSpan {
padding: 2px;
display: inline-block;
text-decoration: underline;
}
<script src="https://ajax.googleapis.com/ajax/libs/jquery/1.9.1/jquery.min.js"></script>
<div id="editor">
A <mark id='1'>businessman</mark> should be able to <mark id='1'>manage</mark> his business matters
</div>
<div id="output">
</div>
The following quick and dirty method removes the spaces from the <mark id='1'> elements so that the whole string can then be split on spaces, allowing individual words to be wrapped as needed, then it's joined back together, and finally the <mark> elements are restored and renumbered:
var text = "A <mark id='1'>businessman</mark> should be able to <mark id='1'>manage</mark> his business matters";
var spanIndex = 1;
var markIndex = 1;
var result = text.replace(/<mark id='1'>/g,'<mark>')
.split(' ')
.map(function(v){
return v.slice(0,6)==='<mark>' ? v : "<span id='" + spanIndex++ + "'>" + v + '</span>'
})
.join(' ')
.replace(/<mark>/g, function() { return "<mark id='" + markIndex++ + "'>"});
console.log(result);
Note: you said you want to "leave the words which are already wrapped in the <mark> tags", but then your sample output had renumbered the mark element ids (input had both as id='1', but output had 1 and 2). So I've shown code that renumbers, but obviously if you didn't mean to do that you can just make the final .replace() a bit simpler.
I took a much simpler approach that uses the browser's native DOM to parse and transform.
The idea here is to:
create an empty element and don't add it to the document.
take your text you want to transform and wrap and set it as the innerHTML of the temp element.
create an array from the childNodes of the temp element (created when you set the innerHTML)
if the childNode has a nodeValue then it was a text node NOT wrapped in a mark tag. In this case, create a new span element
in the case where the node is already wrapped in an element, just return the element
while you do all of this, remap the IDs to the index they were in from the array. this way they are unique.
Since you're settingthe innerHTML of an element, the DOM will actually fix any mistakes and you get perfect HTML out :)
var text = "A <mark id='1'>businessman</mark> should be able to <mark id='1'>manage</mark> his business matters";
const tempElement = document.createElement('div');
tempElement.innerHTML = text;
let final = Array.from(tempElement.childNodes).map((node, index) => {
if (node.nodeValue) { // if the node is a text node
let newSpanElement = document.createElement('span');
newSpanElement.id = index; // assign an ID
newSpanElement.innerText = node.nodeValue;
return newSpanElement;
}
// else it's inside another element
node.id = index; // reassign the id
return node;
}).map(node => node.outerHTML).join('');
console.log(final);
First, I'm creating a library for JavaScript and I can not use jQuery. I'm trying to get the text content of an HTML element without the text contents of its children.
Both attributes innerText and textContent don't give me what needed, please help.
You can solve using DOM API as childNodes and nodeType.
var elChildNode = document.querySelector("#hello").childNodes;
var sChildTextSum = "";
elChildNode.forEach(function(value){
if(value.nodeType === Node.TEXT_NODE) {
console.log("Current textNode value is : ", value.nodeValue.trim());
sChildTextSum += value.nodeValue;
}
});
console.log("All text value of firstChild : ", sChildTextSum);
I created a sample code as above.
https://jsfiddle.net/nigayo/p7t9bdc3/
To get Author's Name from the following element, excluding <span>...:
<div class="details__instructor">
Author's Name<span ng-show="job_title">, Entrepreneur</span>
</div>
use childNodes[0]. For example:
document.querySelector('div.details__instructor').childNodes[0].textContent
Using only JavaScript (you specified you cannot use jQuery), and given that you have provided and know the id for the parent element:
document.getElementById('parent_element_id').childNodes[0].nodeValue;
You can also use .trim() to remove any trailing space characters left behind from the removal of any child element text:
document.getElementById('parent_element_id').childNodes[0].nodeValue.trim();
var mydiv = getElementByID("id");
function Get_text(element) {
var selected = element.cloneNode(true);
var text;
while (selected.firstChild) {
if (selected.firstChild.nodeType == 3) text = selected.firstChild.nodeValue;
selected.removeChild(selected.firstChild);
}
return text;
}
Get_text(mydiv);
I know many good solutions here exist, but none of them actually achieved what I needed (get the textContent of a single node, none of its children), so sharing this for future searchers.
var html = document.getElementsByTagName("*");
for (var i = 0; i < html.length; i++) {
var el = html[i];
for (var j = 0; j < el.children.length; j++) {
var child = el.children[j],
childTextContent = child.innerHTML;
// Remove all children tags, leaving only the actual text of the node.
childTextContent = childTextContent.replace(/\<.*\>.*\<\/.*\>/gmi, "");
// Also remove <img /> type tags.
childTextContent = childTextContent.replace(/\<.*\ \/\>/gmi, "");
console.log(childTextContent);
// Now you can do any type of text matching (regex) on the result.
}
});