Javascript find unparented text within element [duplicate] - javascript

I want to select the text inside the div element and wrap it with a <b> tag. The <b> tag should only wrap to text inside div and not text inside a child element such as the <p> tag in this example.
<div>Testing
<p>Some more text inside p</p>
<p>asdasdasdasdasde p</p>
Test
</div>
I'm able to select the <p> text using the following, but I'm not able to do the same for div. I only want the text of div and not p. For this case it should select and wrap Testing and Test.
var x = $('p')[0].textContent; // this is not working for div.
console.log(x);
JSFiddle

You can use contents, and filter by node type (3 is for text node):
$('div').contents()
.filter(function(){return this.nodeType === 3})
.wrap('<b />');
Example: http://jsfiddle.net/nJqKq/8
See also: Node Types, at MDC

Via pure JS and the DOM:
HTML:
<div id="test">Testing
<p>Some more text inside p</p>
<p>asdasdasdasdasde p</p>
Test
</div>
JS:
getTextNodes(document.getElementById("test"));
function getTextNodes(parent)
{
var textNodes = [];
var nodes = parent.childNodes;
for(var i=0;i<nodes.length;i++)
{
if(nodes[i].nodeType === 3)
{
textNodes.push(nodes[i]);
wrapBold(nodes[i], parent);
}
}
}
function wrapBold(node, parent)
{
//check for whitespace text nodes
if(node.data.match(/[^\t\n\r ]/))
{
var bold = document.createElement("strong");
parent.insertBefore(bold, node);
bold.appendChild(node);
}else
{
return false;
}
}
http://jsfiddle.net/dnjsY/5/

if you dont want to wrap empty nodes use the following:
$('div').contents()
.filter(function(){
return this.nodeType === 3 && this.data.trim().length > 0
}).wrap('<b />');

Related

How to get text values when click if text are not inside html tag?

There is html on the screen that looks like this.
screen:
target1 target2 target3 target4
code:
<div>
target1
<span>target2</span>
<span>target3</span>
target4
</div>
When i click on target4,
I want to get the text "target4"
How do you approach it?
This answer both questions you had
var div = document.querySelector("div"); // get the div wrapper
div.childNodes.forEach(function(node) { // loop over the nodes
var text = node.textContent; // get the text
if (node.nodeName=="#text" && text.trim()!="") { // if text and not empty
var span = document.createElement("span"); // wrap in a span
span.textContent = node.textContent.trim();
node = div.replaceChild(span,node);
}
});
div.onclick=function(e) {
console.log(e.target.textContent);
}
span { color:red }
<div>
target1
<span>target2</span>
<span>target3</span>
target4
</div>
you can get the value of your last text node, this is not a problem. Unfortunately :
childNodes may include text nodes, which don't support event handlers
var x = document.getElementsByTagName("div")[0];
x.addEventListener("click",function(e){
console.log(e.currentTarget.childNodes[4].textContent)});
<div>
target1
<span>target2</span>
<span>target3</span>
target4
</div>
scraaapy has answered your question. But if you have the control over the HTML, then just do this:
HTML
<div>
<span>target1</span>
<span>target2</span>
<span>target3</span>
<span>target4</span>
</div>
JavaScript
var el = document.querySelector("div");
el.addEventListener("click", (e) => {
console.log(e.target.textContent);
});
This way, your code is much easier to maintain and work with. Hope this help!

How do you avoid editing tags inside of tags when replacing characters inside of a tag

So lets say you have HTML that looks something like this:
<p>This text is <b>bold</b></p>
and this Javascript:
var obs = document.getElementsByTagName("p");
var obsreplace = obs[0].innerHTML.replace(/b/gi, "g");
obs[0].innerHTML = obsreplace;
This will change the HTML to this:
<p>This text is <g>gold</g></p>
But what if I want to change it to:
<p>This text is <b>gold</b></p>
and leave the bold tags unchanged?
You'll want to use childNodes, and run your replace against each of those. That will capture text nodes separately from elements. By recursively looping through each child element until there are only text nodes left, you can safely run your replace command against all text in the element.
function safeReplace(elem, replaceFn){
let nodes = elem.childNodes, i = -1
while(++i < nodes.length){
let node = nodes[i]
if(node.nodeType == 3){ //signifies a text node
node.textContent = replaceFn(node.textContent)
} else {
safeReplace(node, replaceFn)
}
}
}
document.querySelector('button').addEventListener('click', function(){
safeReplace(document.getElementById('testDiv'), function(str){
return str.replace(/e/gi, '_E_')
})
})
<div id="testDiv">
This div has outer content, as well as <p>a paragraph containing a <span>spanned text</span> in the middle</p>More text.</div>
<button>Replace Text</button>
So, two solutions, replace with regex keeping the matched groups, or use the getElementsByTagName? For sure you have to check the length of obs and bold before doing any operation on the elements, making sure there are no errors.
var obs = document.getElementsByTagName("p");
var bold = obs[0].getElementsByTagName("b")[0];
bold.innerHTML = "gold";
var obs = document.getElementsByTagName("p");
var replaceHtml = obs[1].innerHTML.replace(/(<b>).*?(<\/b>)/, "$1gold$2");
obs[1].innerHTML = replaceHtml;
<p>This text is <b>bold</b></p>
<p>This text is <b>bold</b></p>

Get all text contents of a DOM element outside its children using Javascript

I have a DOM element that has some number of children, interleaved by text strings.
I want to get each of these text strings, and replace them using regex.
For example:
<div>Text started.
<a>Link child inside</a>
Some more text.
<u>Another child</u>
Closing text.</div>
In this example, I want to extract the strings "Text started.", "Some more text.", and "Closing text.", so that I can replace each of them later with something else.
The solution should be generic since the number of children inside the parent can vary, and the node types as well.
Anyone got a clever answer to achieve this easily using javascript?
You can use childNodes to check if the nodeType is a text node.
Doing this inside a forEach you can easily replace the text with whatever you want.
Example:
var div = document.getElementsByTagName('div').item(0);
[].slice.call(div.childNodes).forEach(function(node , i) {
if(node.nodeType === 3) {
var currNode = div.childNodes[i];
var currText = div.childNodes[i].textContent;
currNode.textContent = currText.replace(/text/i, ' Foo');
}
})
<div>
Text started.
<a>Link child inside</a>
Some more text.
<u>Another child</u>
Closing text.
</div>
You can do as follows;
var textNodes = [...test.childNodes].filter(child => child.nodeType === Node.TEXT_NODE)
textNodes.forEach(tn => console.log(tn.textContent))
<div id="test">Text started.
<a>Link child inside</a>
Some more text.
<u>Another child</u>
Closing text.</div>

Jquery remove the innertext but preserve the html

I have something like this.
<div id="firstDiv">
This is some text
<span id="firstSpan">First span text</span>
<span id="secondSpan">Second span text</span>
</div>
I want to remove 'This is some text' and need the html elements intact.
I tried using something like
$("#firstDiv")
.clone() //clone the element
.children() //select all the children
.remove() //remove all the children
.end() //again go back to selected element
.text("");
But it didn't work.
Is there a way to get (and possibly remove, via something like .text("")) just the free text within a tag, and not the text within its child tags?
Thanks very much.
Filter out text nodes and remove them:
$('#firstDiv').contents().filter(function() {
return this.nodeType===3;
}).remove();
FIDDLE
To also filter on the text itself, you can do:
$('#firstDiv').contents().filter(function() {
return this.nodeType === 3 && this.nodeValue.trim() === 'This is some text';
}).remove();
and to get the text :
var txt = [];
$('#firstDiv').contents().filter(function() {
if ( this.nodeType === 3 ) txt.push(this.nodeValue);
return this.nodeType === 3;
}).remove();
Check out this fiddle
Suppose you have this html
<parent>
<child>i want to keep the child</child>
Some text I want to remove
<child>i want to keep the child</child>
<child>i want to keep the child</child>
</parent>
Then you can remove the parent's inner text like this:
var child = $('parent').children('child');
$('parent').html(child);
Check this fiddle for a solution to your html
var child = $('#firstDiv').children('span');
$('#firstDiv').html(child);
PS: Be aware that any event handlers bounded on that div will be lost as you delete and then recreate the elements
Why try to force jQuery to do it when it's simpler with vanilla JS:
var div = document.getElementById('firstDiv'),
i,
el;
for (i = 0; i< div.childNodes.length; i++) {
el = div.childNodes[i];
if (el.nodeType === 3) {
div.removeChild(el);
}
}
Fiddle here: http://jsfiddle.net/YPKGQ/
Check this out, not sure if it does what you want exactly... Note: i only tested it in chrome
http://jsfiddle.net/LgyJ8/
cleartext($('#firstDiv'));
function cleartext(node) {
var children = $(node).children();
if(children.length > 0) {
var newhtml = "";
children.each(function() {
cleartext($(this));
newhtml += $('<div/>').append(this).html();
});
$(node).html(newhtml);
}
}

Jquery Hide Class when no class is present

I have some text below called (16 Courses). I need to hide only this text, but I can't seem to hide it no matter what I try using jquery. Is there any help someone could provide so I can hide on this text?
<div id="programAttributes">
<div class="left" id="credits">
<h3>Credits</h3>
<h3 class="cost">48</h3>
(16 Courses)
</div>
<div class="gutter12 left"> </div>
<div class="left" id="costPer">
<h3>Cost Per Credit</h3>
<h3 class="cost">$300</h3>
</div>
</div>
I thought if I could write something like this that would do the trick, but I am so far unsuccessful.
$("#credits:not([class!=h3])").hide();
Usage
// hides in the whole document
hideText("(16 Courses)");
// only hide inside a specific element
hideText("(16 Courses)", $('#programAttributes'));
// make it visible again
showText("(16 Courses)");
[See it in action]
CSS
.hiddenText { display:none; }
Javascript
// escape by Colin Snover
RegExp.escape = function(text) {
return text.replace(/[-[\]{}()*+?.,\\^$|#\s]/g, "\\$&");
}
function hideText(term, base) {
base = base || document.body;
var re = new RegExp("(" + RegExp.escape(term) + ")", "gi");
var replacement = "<span class='hiddenText'>" + term + "</span>";
$("*", base).contents().each( function(i, el) {
if (el.nodeType === 3) {
var data = el.data || el.textContent || el.innerText;
if (data = data.replace(re, replacement)) {
var wrapper = $("<span>").html(data);
$(el).before(wrapper.contents()).remove();
}
}
});
}
function showText(term, base) {
var text = document.createTextNode(term);
$('span.hiddenText', base).each(function () {
this.parentNode.replaceChild(text.cloneNode(false), this);
});
}
You can check for and remove textnodes like this:
​$("#credits").contents().filter(function() {
if(this.nodeType == 3)
this.parentNode.removeChild(this);
});​​​​​​
You can test it here, this gets all the nodes (including text nodes) with .contents(), then we loop through, if it's a text node (.nodeType == 3) then we remove it.
Could you wrap it in a separate span, and then do:
$('#credits span').hide();
?
Try wrapping the text in a span as follows:
<div class="left" id="credits">
<h3>Credits</h3>
<h3 class="cost">48</h3>
<span id="toHide">(16 Courses)</span>
</div>
then you can use jquery:
$("#credits > span)").hide();
the hide() function has to be applied to a DOM element.
I would use a label tag around the text so I can handle it with jquery.
It's textnode. Loop thru all parents nodes and if it's type is textnode, hide it. See also this:
How do I select text nodes with jQuery?

Categories

Resources