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);
}
}
Related
I want to remove the elements where there is no content. For example this is my HTML markup:
I have the html markup in a jquery variable say var myhtml and I am not sure of any specific tags in it.
<h1>
<u>
<strong></strong>
</u>
<u>
<strong>Read This Report Now
<strong></strong> ??
</strong>
</u>
</h1>
As we can see that above markup
<u>
<strong></strong>
</u>
is empty and hence this should be removed from the markup. Say I have the above markup in a variable myhtml. How can I do this?
I am not sure if the element will be either
"<u>" or "<em>" or "<i>" or "<div>" or "<span>"
.. It can be anything.
You can search all elements and remove which is empty.
$('*').each(function(){ // For each element
if( $(this).text().trim() === '' )
$(this).remove(); // if it is empty, it removes it
});
See how works!: http://jsfiddle.net/qtvjj3oL/
UPDATED:
You also can do it without jQuery:
var elements = document.getElementsByTagName("*");
for (var i = 0; i < elements.length; i++) {
if( elements[i].textContent.trim() === '' )
elements[i].parentNode.removeChild(elements[i]);
}
See jsfiddle: http://jsfiddle.net/qtvjj3oL/1/
UPDATED 2:
According to your comment, you have the html in a variable, you can do it:
// the html variable is the string wich contains the html
// We make a fake html
var newHtml = document.createElement('html');
var frag = document.createDocumentFragment();
newHtml.innerHTML = html;
frag.appendChild(newHtml);
var elements = newHtml.getElementsByTagName("*");
// Remove the emptys elements
for (var i = 0; i < elements.length; i++) {
if( elements[i].textContent.trim() === '' )
elements[i].parentNode.removeChild(elements[i]);
}
html = newHtml.innerHTML; // now reset html variable
It works: http://jsfiddle.net/qtvjj3oL/6/
try
$("u").each(function () { // if remove all, you can select all element $("*")
var x = $(this).text().trim();
if (x == "") {
$(this).remove();
}
});
IF you want remove everything simply you can use empty selector then remove it
DEMO
JQuery
It searches all elements and remove all blank elements (ie: <span></span>), all elements which contains a simple space (ie: <span> </span>) and all elements which contains only a (ie: <span> </span>)
$(".mydiv *").each(function() {
var $this = $(this);
if($this.html().replace(/\s| /g, '').length == 0)
$this.remove();
});
DEMO: http://jsfiddle.net/7L4WZ/389/
simply:
$( ":empty" ).remove();
or
$( "u:empty" ).remove();
if specific
You can use .filter() and remove() for this
$('*').filter(function() {
return $(this).text().trim() == ""
}).remove();
If your html is already in a variable myhtml here is how you would do it:
$('*', myhtml).filter(function() {
return $(this).text() == '';
}).remove();
How can we change the text data from except span text?
<h2 id="nameUser" >Muhammed <span> mobile :989 531 9991</span></h2>
Is there any solution to change h2 except span?
.contents() returns a collection of nodes, including text nodes. So in your case this would work:
$('#nameUser').contents()[0].nodeValue = 'Another name';
If you want to get every node except the SPAN, try:
$('#nameUser').contents().filter(function() {
return this.nodeName != 'SPAN';
}).each(function(i) {
// modify each text node
this.nodeValue = 'name '+i;
});
DEMO: http://jsfiddle.net/Vks82/
Search for the first textnode in childNodes of the h2 element. Change the value of the textnode.
var element = document.getElementById('nameUser');
element.childNodes[0].nodeValue = 'New String';
..should work. Only for this example, because the first childnode is the textnode you want, you don't have to search for it. Otherwise you do..
This example may help you to change father element without changing child elements:
var content= $('#nameUser').children();
$('#nameUser').text('Altered Text').append(content);
$('#nameUser').contents().each(function() {
if (this.nodeType == 3)
this.data = "The text you want here";
});
Live DEMO
You can do it by saving the children first here is a codepen of it working.
http://codepen.io/beckje01/pen/sGLot
var h2 = $('#nameUser');
var elmsToSave = h2.children();
h2.empty();
h2.text('bob');
h2.append(elmsToSave);
As pointed out in the comments this will only work if the text to change is first.
This will work not only for span but also for any other element which you want the text without the text of it's children.
$("#nameUser")
.clone()
.children()
.remove()
.end()
.text();
For change the text I've create a simple jQuery function:
replaceTextWith = function($element, $replacement){
$oldText = $element.clone().children().remove().end().text();
$element.text($element.text().replace($oldText, $replacement));
}
replaceTextWith($("#nameUser"), "Bruno"); //usage
Here's a live example working on fiddle
try this ...
<h2 id="nameUser" >Muhammed <span id="nameUserSpan"> mobile :989 531 9991</span></h2>
<script>
$(document).ready(function() {
var inspan= $("#nameUserSpan").html();
var newuser='New User';
$("#nameUser").html('');
$("#nameUser").html(newuser + '<span id="nameUserSpan">' + inspan + '</span>');
});
</script>
for example we have this file
<div id="mydiv">
some text here
<div id="inner div">
text for inner div
</div>
</div>
i need to get #mydiv text only with some code like this :
alert($('#mydiv').text()); // will alert "some text here"
hey try this please": http://jsfiddle.net/MtVxx/2/
Good link for your specific case in here: http://viralpatel.net/blogs/jquery-get-text-element-without-child-element/ (This will only get the text of the element)
Hope this helps, :)
code
jQuery.fn.justtext = function() {
return $(this).clone()
.children()
.remove()
.end()
.text();
};
alert($('#mydiv').justtext());
The currently accepted answer is pretty horrible in terms of performance, so I felt obligated to write a more lightweight one:
$.fn.mytext = function() {
var str = '';
this.contents().each(function() {
if (this.nodeType == 3) {
str += this.textContent || this.innerText || '';
}
});
return str;
};
console.log($('#mydiv').mytext());
Like Ja͢ck's answer but no need for iterating explicitly (via .each()) and collecting textContents:
$('#mydiv').contents().filter(function(){return this.nodeType === 3}).text()
OR, if you can use arrow functions:
$('#mydiv').contents().filter((i, el) => el.nodeType === 3).text()
I was able to get this partially working using the :contains selector, but my problem is if an element contains an element that contains the text it is still returned. For example:
$('div:contains("test")')
Will select both divs below:
<div>something else
<div>test</div>
</div>
fiddle: http://jsfiddle.net/TT7dR/
How can I select only divs that "directly" contain the text? Meaning that in the above example only the child div would be selected.
UPDATE:
Just to clarify, if I were searching for the text "something else" instead of "test" then I would like to only find the parent div.
$('div>:contains("test")') is not a general solution, it only works for your specific example. It still matches any element whose descendants contain the text test, as long as its parent is a div.
There is in fact currently no selector that will select only direct parents of text nodes containing your target text. To do it you would have to walk the DOM tree yourself checking each text node you find for the target text, or write a plugin to do the same. It'd be slow, but then not as slow as :contains already is (it's not a standard CSS selector so you don't get browser-native fast selector support).
Here's a plain DOM function you could use as a starting point. It might be improved to find text in adjacent (non-normalised) text nodes, or to hide it in a plugin/selector-extension.
function findElementsDirectlyContainingText(ancestor, text) {
var elements= [];
walk(ancestor);
return elements;
function walk(element) {
var n= element.childNodes.length;
for (var i= 0; i<n; i++) {
var child= element.childNodes[i];
if (child.nodeType===3 && child.data.indexOf(text)!==-1) {
elements.push(element);
break;
}
}
for (var i= 0; i<n; i++) {
var child= element.childNodes[i];
if (child.nodeType===1)
walk(child);
}
}
}
Just to complete the knowledge base. If you need to get all DOM elements within the body (not only DIVs) that contain specific text or characters you can use:
function getNodesThatContain(text) {
var textNodes = $(document).find(":not(iframe, script)")
.contents().filter(
function() {
return this.nodeType == 3
&& this.textContent.indexOf(text) > -1;
});
return textNodes.parent();
};
console.log(getNodesThatContain("test"));
Hope that helps.
jsfiddle: http://jsfiddle.net/85qEh/2/
Credits: DMoses
You might have to do an in-efficient query. Do not use this solution if someone finds a selector that manages to filter out child elements: http://viralpatel.net/blogs/2011/02/jquery-get-text-element-without-child-element.html
$("div:contains('test')")
.clone() //clone the element
.children() //select all the children
.remove() //remove all the children
.end() //again go back to selected element
.filter(":contains('test')")
edit: that snippet above is just to test the element, in implementation it would look more like this: http://jsfiddle.net/rkw79/TT7dR/6/
$("div:contains('test')").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('test')").length > 0)
}).css('border', 'solid 1px black');
try adding the greater than:
$('div>:contains("test")')
Finds specific element, but not parents
var elementsContainingText = ($(':contains("' + text + '")', target)).filter(function() {
return $(this).contents().filter(function() {return this.nodeType === 3 && this.nodeValue.indexOf(text) !== -1; }).length > 0;
});
This seems to work for me:
$('div >:contains("test")');
http://jsfiddle.net/TT7dR/1/
This forces the matched :contains selector to be a direct child of the <div> element
Try the following:
$("div>div:contains(test):only-of-type")
Add more alternative:
if($(selector).text().trim().length) {
var thetext = $(selector).contents().filter(function(){
return this.nodeType === 3;
}).text().trim();
console.log(thetext);
}
It will select the text only and remove any element with tag!
Reference
You can simply select the element that doesn't have your element
$('div:contains("test"):not(:has(> div))')
less code to write (but with a little limitation):
let selector = $('div:contains("test")');
selector.not(selector.has('div:contains("test")'))
Just use the jQuery function (.has) because the css :has is experimental:
https://developer.mozilla.org/en-US/docs/Web/CSS/:has#Browser_compatibility
Limitation:
When you have a structure like this:
<div>
<div>test</div>
test
</div>
Then only the inner div - Element will be found by this solution. This is because there is still an Element - Child of the div that :contains the string "test".
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?