How to get only directly contained text in DOM element in Javascript? - javascript

I have a div with some children within and its directly contained text like below:
<div id="price">
100$
<span>some ads</span>
<span>another ads</span>
for each
</div>
I want to get directly contained text '100$' in this DOM element.
I tried with innerHTML, innerText and textContent.
But they show all text including children's text like below:
const element = document.getElementById('price');
console.log(element.innerText);
console.log(element.innerHTML);
console.log(element.textContent);
<div id="price">
100$
<span>some ads</span>
<span>another ads</span>
for each
</div>
The expected result is 100$(I don't need "for each") which is directly contained text in parent element. So then I can get the price and its currency.
note: jquery is also allowed to use.

.clone() clones the selected element.
.children() selects the children from the cloned element
.remove() removes the previously selected children
.end() selects the selected element again
.text() gets the text from the element without children
const elementText = $("#price").clone()
.children()
.remove()
.end()
.text();
console.log(elementText.trim().split("\n")[0]);
<script src="https://cdnjs.cloudflare.com/ajax/libs/jquery/3.3.1/jquery.min.js"></script>
<div id="parent">
Parent
<span>Child 1</span>
<span>Child 2</span>
</div>
<div id="price">
100$
<span>some ads</span>
<span>another ads</span>
for each
</div>
EDIT: You can also use this:
$("#price").contents().get(0).nodeValue.trim()

Filter the childNodes to include only text nodes and use textContent of each of the matching nodes:
const text = Array.prototype.filter
.call(element.childNodes, (child) => child.nodeType === Node.TEXT_NODE)
.map((child) => child.textContent)
.join('');
The text includes the full markup of the text, including newlines. If this is undesired, use text.trim().
The filter.call is used because childNodes is a NodeList, which is array-like, but does not support .filter method.
To get text only for the first node
const text = Array.prototype.filter
.call(element.childNodes, (child) => child.nodeType === Node.TEXT_NODE)[0];
Alternatively, if you can rely on the fact that the value is always the first child, the above can be simplified to
const text = element.childNodes[0];

With jQuery :
const text = $($('#price').contents()[0]).text().trim();

You can do this using the "outerText" property. Like in the example below:
var text = document.querySelector('body').outerText;
var regex = /([\d]+)\$/g;
console.log(text.match(regex).join());
<div id="price">
100$
<span>some ads</span>
<span>another ads</span>
for each
</div>

Related

How do I get all child text from a div and separate with a space?

Say I have this:
<div id ="element">
<span>Hey</span>
<div>
<span>What up?</spa>
</div>
Yeah more text here.
</div>
How can I get all of the text in the note and it's descendants in a single text line with a space between each new child? I am looking for.
'Hey What up? Yeah more text here.'
I tried:
var text = document.getElementById("element").textContent;
But that makes all the words bunched up like.
'HeyWhat up?Yeah more text here.'
Note the amount of child elements is dynamic and it might just be 5 or 100.
You can loop over all the child nodes recursively to find text nodes.
const div = document.querySelector("#element");
const text = [];
div.childNodes.forEach(function check(child){
if(child.nodeType === Node.TEXT_NODE){
text.push(child.nodeValue.trim());
}
child.childNodes.forEach(check);
});
console.log(text.join(' '));
<div id ="element">
<span>Hey</span>
<div>
<span>What up?</span>
</div>
Yeah more text here.
</div>
const text = document.querySelector("#element").textContent.replace(/\s+/g, " ").trim();
console.log(text);
<div id="element">
<span>Hey</span>
<div>
<span>What up?</spa>
</div>
Yeah more text here.
This is <u>Nice</u>
<i>One</i>
<div>
<p><b>!</b></p>
</div>
</div>

Get div value from class name

I have a very large HTML that contains lots of divs with the same name, I want a way to only filter or extract that value from that div.
Here is an example:
<td class="last">
<div class="container-relative">
<div class="name" title=""User" <John Appleseed>"></div>
<div class="date">9/17/2019</div>
<div class="tool"></div>
</div>
</td>
I need to extract only what's between <John Appleseed>, in this case is 'John Appleseed'.
You could use querySelectorAll to take all the elements with class name, then get the title attribute with getAttribute, and finally use a regular expression to match text between <>.
document.querySelectorAll('.name').forEach(item => {
let title = item.getAttribute('title');
console.log(title.match(/\<.*\>/));
});
<td class="last">
<div class="container-relative">
<div class="name" title=""User" <John Appleseed>"></div>
<div class="date">9/17/2019</div>
<div class="tool"></div>
</div>
</td>
var divs=[];
for(i=0,j=0,obj=document.getElementsByClassName("name");i<obj.length;i++)
if(obj[i].title.includes("John Appleseed") &&
/* obj[i].title.split("\"")[2].trim()=="<John Appleseed>" && */
obj[i].tagName.toLowerCase()=="div"){
divs[j++]=obj[i];
}
console.log(divs);
separate your div using div ID. Then get your respective div using that value of ID. Then in javascript you can use getElementByID.
You can use Xpath,
.//div[contains(#class, 'Test')]
Then extract you required text from it.

Getting text content of a div element excluding its children

I have the following HTML code and I need to console.log only Shipping.
I tried a few methods but can't seem to get it to work.
I tried selecting first its children and printing out the textContent of its parent - no go. I could delete its children and print out what's left but I can't do that.
Any suggestions?
<div class="accordion shadowed-box shipping collapsed summary">
<fieldset>
<legend>
Shipping
<div id="shippingTooltip" class="form-field-tooltip cvnship-tip" role="tooltip">
<span class="tooltip">
<div class="tooltip-content" data-layout="small tooltip-cvn">
<div id="cart-checkout-shipping-tooltip" class="html-slot-container">
<p>We ship UPS, FedEx and/or USPS Priority Mail.<br>
<a class="dialogify" data-dlg-options="{"height":200}" href="https://www.payless.com/customer-service/ordering-and-shipping/cs-ordering-shipping-schedule.html" title="shipping information">Learn more about our shipping methods and prices.</a>
</p>
</div>
</div>
</span>
</div>
Edit
</legend>
</fieldset>
</div>
I tried this:
var accordionChildren = document.querySelector('.accordion.shadowed-box.shipping>fieldset>legend *');//selects the first child
var accordionTitle = accordionChildren.parentElement;
var text = accordionTitle.textContent;
console.log(text);
I want to get Shipping but instead I get still all the text contents of the legend element.
you can access Text nodes by iterating over the child nodes (or access the intended node directly) of the accordionTitle variable.
let textNode = accordionTitle.childNodes[0],
text = textNode.textContent;
console.log(text);
See https://developer.mozilla.org/en-US/docs/Web/API/Node/childNodes and https://developer.mozilla.org/en-US/docs/Web/API/Text
You just need to find the TextNode child from all of the elements children, you do this by iterating over all of the childNodes and when the node type matches TextNode, return its textContext.
For a jQuery based solution on how to pick the TextNode child of an element see this question - but my example shows how to do it in vanilla ES (with a for loop over childNodes):
Object.defineProperty(HTMLElement.prototype, 'onlyTextContent', {
enumerable: false,
configurable: false,
get: function() {
for(let i = 0; i < this.childNodes.length; i++) {
if(this.childNodes[i].nodeType === Node.TEXT_NODE) {
return this.childNodes[i].textContent.trim();
}
}
return null;
}
});
document.addEventListener('DOMContentLoaded', function() {
console.log(
document.getElementById('legend1').onlyTextContent
);
});
<div class="accordion shadowed-box shipping collapsed summary">
<fieldset>
<legend id="legend1">
Shipping
<div id="shippingTooltip" class="form-field-tooltip cvnship-tip" role="tooltip">
<span class="tooltip">
<div class="tooltip-content" data-layout="small tooltip-cvn">
<div id="cart-checkout-shipping-tooltip" class="html-slot-container">
<p>We ship UPS, FedEx and/or USPS Priority Mail.<br>
<a class="dialogify" data-dlg-options="{"height":200}" href="https://www.payless.com/customer-service/ordering-and-shipping/cs-ordering-shipping-schedule.html" title="shipping information">Learn more about our shipping methods and prices.</a>
</p>
</div>
</div>
</span>
</div>
Edit
</legend>
</fieldset>
</div>
You can get the contents of the <legend> tag as a string and then use a regular expression to remove the HTML tags and their content inside. Like this:
let legends = document.querySelector('.accordion.shadowed-box.shipping>fieldset>legend');
let title = legends.innerHTML.replace(/<.*/s, '');
// title = "Shipping"
The regular expression matches the first < character and everything that follows. So we replace that match with an empty string ''.

jQuery : Split the DOM Node using jQuery

My problem is to split the Dom element using jquery.
<span class="start">
<span class="second">
new text <span class='split'>is written</span> in this place.
</span>
</span>
And I want to Split the above DOM Like this.
<span class="start"><span class="second">new text</span></span>
<span class="start"><span class="second">is written</span></span>
<span class="start"><span class="second">in this place.</span></span>
Please, anybody give me some advice.
One way to do it would be:
last_text=$('.split')[0].nextSibling; //get textNode after split span
prev_text=$('.split')[0].previousSibling; //get text Node before split span
current=$('.split').text(); //get split span text
$('.second').html(' '); //clear current html
cloned1=$('.start').clone(); // clone el
cloned1.insertAfter($('.start'));
cloned2=$('.start').first().clone(); //clone one more
cloned2.insertAfter($('.start').last());
//set text for elements
$('.start .second').eq(0).html(prev_text);
$('.start .second').eq(1).html(current);
$('.start .second').eq(2).html(last_text);
Demo:
last_text=$('.split')[0].nextSibling; //get textNode after split span
prev_text=$('.split')[0].previousSibling; //get text Node before split span
current=$('.split').text(); //get split span text
$('.second').html(' '); //clear current html
cloned1=$('.start').clone(); // clone el
cloned1.insertAfter($('.start'));
cloned2=$('.start').first().clone(); //clone one more
cloned2.insertAfter($('.start').last());
//set text for elements
$('.start .second').eq(0).html(prev_text);
$('.start .second').eq(1).html(current);
$('.start .second').eq(2).html(last_text);
<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js"></script>
<span class="start">
<span class="second">
new text <span class='split'>is written</span> in this place.
</span>
</span>
P.S. If there are no classes (i guess that could be the case), you will have to use different selectors, to target spans (inside container?), with eq(), maybe, but, basically, this simple logic should work...

How to select leaf node using jQuery :contains selector?

I want to get leaf elements containing specific text, and I used :contains selector. However, this selector selects includes every parent nodes too. Here is my example.
<div id='parent1'>
<p id='target1'>Red balloon</p>
<div id='target2'>Blue balloon</div>
</div>
<div id='parent2'>
<span id='target3'>Brown balloon</span>
</div>
In this case, I just want to get elements containing text balloon. I expected to get 3 elements(target1, target2, target3) by $(":contains('balloon')"), but it returns every nodes including parent nodes of targets. (e.g. html, body, and every parent div)
How can I select only targets?
p.s Above HTML is only example. HTML can be vary, so the answer should be generic.
use indexOf("balloon") > -1 to find id the word balloon is found
var arr = $("div").children().map(function(){
if($(this).text().indexOf("balloon") > -1 )
return $(this).attr("id")
}).get();
console.log(arr)
<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js"></script>
<div id='parent1'>
<p id='target1'>Red balloon</p>
<div id='target2'>Blue balloon</div>
</div>
<div id='parent2'>
<span id='target3'>Brown balloon</span>
</div>
The solution below, look for all elements containing the word and clone these elements, This way we can be sure only to get "correct" amount of elements
Just remove .length and you have access to the elements.
var s = $(":contains('balloon')").not("script").filter(function() {
return (
$(this).clone() //clone the element
.children() //select all the children
.remove() //remove all the children
.end() //again go back to selected element
.filter(":contains('balloon')").length > 0)
}).length;
console.log(s)
<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js"></script>
<div id='parent1'>
<p id='target1'>Red balloon</p>
<div id='target2'>Blue balloon</div>
</div>
<div id='parent2'>
<span id='target3'>Brown balloon</span>
</div>

Categories