jQuery replace text leaving siblings intact - javascript

I'm having trouble wrapping my head around what should be a simple solution. I want to replace text within a label tag, without affecting the other 'siblings', if they exist.
Sample markup:
<fieldset class="myFieldsetClass">
<legend>Sample Fieldset</legend>
<ol>
<li>
<label>
<span class="marker">*</span>
Some Label 1
</label>
</li>
<li>
<label>
Some Label 2
</label>
</li>
<li>
<label>
Text that doesn't match...
</label>
</li>
</ol>
</fieldset>
Goal:
To replace text Some Label X with Some Label (I.e. remove X from the label text).
span tags within label must stay intact if they exist, such as the <span class="marker"> above.
I do not know the value of X, which could be 1 or more characters long.
Current Script:
My jQuery script below works, but I know is very inefficient. I can't seem to wrap my head around this one for some reason...
//for each label in the fieldset that contains text "Some Label "
$(".myFieldsetClass label:contains('Some Label ')").each(function() {
if ($(this).has("span").length > 0) {
//if the label has the span tag within, remove it and prepend it back to the replaced text
$(this).find("span").remove().prependTo($(this).text(labelText));
}
else {
//otherwise just replace the text
$(this).text('Some Label');
}
});
I thought at first I could simply do:
$(".myFieldsetClass label:contains('Some Label ')").text("Some Label");
But this clears all contents of the label and hence removes the span, which I don't want. I can't use any replace functions to replace Some Label X with Some Label because I don't know what X will be.
Can anyone suggest a more elegant/efficient approach to this problem?
Thanks.
EDIT
After trying multiple answers, I think the problem seems to be that even if I select the right collection, they are text nodes, which jquery doesn't seem to want to modify.. I've used FireBug to select the collection (many answers below all select correctly but in slightly different ways). In firebug console resulting set is:
[<TextNode textContent="Some Label 1:">,
<TextNode textContent="Some Label 2:">,
<TextNode textContent="Some Label 3:">,
<TextNode textContent="Some Label 4:">,
<TextNode textContent="Some Label 5:">]
The problem seems to be that calling .replaceWith(), .replace(), .text(), etc. doesn't seem to affect the jquery collection. If I allow the above collection to contain one of the spans, then calling .replaceWith(), .replace(), etc functions correctly against the span, but the text nodes stay as is..

Try:
$(".myFieldsetClass label:contains('Some Label ')").contents().filter(':last-child').text("Some Label");
This should work assuming the text to be replaced will always be at the end. The contents() function selects all nodes, including text nodes.
http://api.jquery.com/contents/
EDIT: I should have used filter() instead of find(). Corrected.
EDIT: Works now. Here's one way.
// Store proper labels in a variable for quick and accurate reference
var $labelCollection = $(".myFieldsetClass label:contains('Some Label ')");
// Call contents(), grab the last one and remove() it
$labelCollection.each(function() {
$(this).contents().last().remove()
});
// Then simply append() to the label whatever text you wanted.
$labelCollection.append('some text')

As patrick points out, you can use contents() to select the text alone, and then do a replace on it all. Adapting the example given there, you could also try:
$(".myFieldsetClass label:contains('Some Label ')").contents().filter(function() {
return this.nodeType == 3 && $(this).is(":contains('Some Label ')");
})
.replaceWith("Some Label");
However, if you know that "Some Label " will always be the last element in the <label> then patrick's method will be faster I believe.

Why not simply do an entire replace using regex?
$(".myFieldsetClass label:contains('Some Label ')")
.each(function() {
$(this).html($(this).html().replace(/Some Label ./, "Some Label"));
});

A one-liner:
$('.myFieldsetClass label').contents().last().remove().end().first().after('New Label')

Related

Specify optional element in XPath path?

Consider the following HTML:
<div>
text1
</div>
<div>
<span>
text2
</span>
</div>
<div>
text3
</div>
I need to select all the nodes with text1/text2/text3. When I use
/html/body/div[position() > 0]
I obviously don't get the span around text2, but the div around <span>text2</span>. How can I say: If there is a span following the div, then return the span; if the div is already the last element in a path, return the div? So the intended nodes would be:
div[0]
div[1]/span
div[2]
Update: This one works, but is there a shorter way to do it? (e.g. I am writing /html/body/divin both of them, is it possible to make the pipe symbol (or) at a later place?)
/html/body/div[position() > 0 and count(*) = 0] | /html/body/div[position() > 0]/span
I order to select a node with text content in it, you can use the text() selector.
So if you want select all nodes with some text content form a root node, you can use this xpath selector:
//ROOT_NODE//text()
So, for your example and as you said in your comment:
/html/body/div//text()

replace all specific character inside div with jquery

I'm trying to replace all the commas (",") inside the div with a character. I've tried googling and it seems .replace() replaces only the first comma and it removes the links from the text1.
How do I replace all the commas with another character inside the div without it removing the links, using jquery?
<div>
text1, text2, text3, text4,
</div>
Get all text node inside the div and update it, that will be the better way than updating entire html inside div.
$('div')
.contents() // get all child nodes
.each(function() { // iterate over them
if (this.nodeType == 3) // check node type is text
this.textContent = this.textContent.replace(/,/g, '+'); // update text content if it's text node
})
<script src="https://ajax.googleapis.com/ajax/libs/jquery/1.11.1/jquery.min.js"></script>
<div>
text1, text2, text3,
</div>
It will replace all , with 'a' character. use of the "g" within this - that stands for "global" and causes the replacing of all of the target characters in the string - without it you just replace the first instance as you have discovered. try it.
string.replace(/\,/g, 'a');

How to add spans to all areas of a node that isn't restricted

This is a continuation of What's a good way to show parts of an element but hide the rest?
<h1>
Let's say you had this <span class="safe">text</span>.
</h1>
How could one wrap all non-safe regions in an element with a disappear class (with jQuery).
Final Output
<h1>
<span class="disappear">Let's say you had this </span>
<span class="safe">text</span>
<span class="disappear">.</span>
</h1>
That way, the parent node is still visible, but the non-safe regions disappear, leaving the safe.
I'm not sure how to do this, but surely it's possible.
Text nodes have a nodeType of 3. Iterate the nodes and use wrap() to wrap the text nodes.:
$someElement.contents().each(function() {
if (this.nodeType == 3)
$(this).wrap('<span class="disappear" />');
});
http://jsfiddle.net/SnjnJ/
Filter the textNodes and wrap them in spans :
$('h1').contents().filter(function() {
return this.nodeType === 3;
}).wrap('<span class="disappear" />');
FIDDLE
$('h1').children().not('.safe').hide();
http://jsfiddle.net/VeSCw/
Match all contents of the h1 and use .not() to remove the safe from your selection. Then use .wrap() to make them "disappear".
http://api.jquery.com/not/

Reading a value from 'this' instance in jQuery

When I am printing 'this' instance in alert box, it is printing something like this.
[object Object]
But the actual content in it is
<dl>
<dt>
my Name <span> John Krishna </span>
</dt>
<dd>
<span>My fathers name</span>
</dd>
</dl>
I want to display only 'my Name' instead of [object Object]. I mean what ever content of span in that 'dt' I want to display it in my alert box.
For this I tried out around in google, every where I am getting solutions like use child, or using inner html content and in some solutions someone written for loops. But I don't want to write any for loops around it which makes my code large.
Some one please suggest me some way that how can I print only "my Name" in alert box.
It depends on how you did the selection. If it is on the whole dl tag, than it should be something like this
alert($("dl").find("dt").clone().find("span").remove().end().html());
Where dl is an example selection. I don't know how you get it (by id, class etc.)
if you're selecting dt tag directly, than you should use a shorter version
alert($("dt").clone().find("span").remove().end().html());
It sounds to me like you're trying to alert an entire object. You'll need to make use of jQuery's text() method to display only the element's text.
If this is already selecting the span element you're after, you can simply use:
alert($(this).text()); // Instead of alert($(this));
I need only text inside 'dt' and content inside span should not be printed
For this we can use a regular expression to replace the <span> content from the dt element's HTML:
alert($('dt').html().replace(/<span>.*<\/span>/,''));
Here's a JSFiddle demo of this in use.
This is 96% faster than using cloning the element as some of the other answers below have suggested.
Add an id to the span (e.g. <span id="myname">Test Name</span>) and then match on the id in jQuery (using $("#myname")) and alert the text of that element to return what you need.
For example:
alert($("myname").text());
try to map : collecting them into an array instead of two calls to $:
var texts = $('span').map(function(){
return this.previousSibling.nodeValue
});
texts[0]; // "Some text followed by "
texts[1]; // " and another text followed by "
alert(texts[0]);
Hope it will help
you will need to use:
$(this).html();
try this:
var name=$(this).children('dt').children('span').text();
alert('name --->'+name);
Thanks
Use:
alert($(this).find("dt span").text());
Getting the text outside of the span is a little tricky in jQuery. I found this code here:
var myName = $(this).find("dt")
.clone() //clone the element
.children() //select all the children
.remove() //remove all the children
.end() //again go back to selected element
.text();

jQuery: Returning the text from first-child or self

I am trying to get the text inside an element and I only want to get the text if it's inside the first-child of a placehoder div or if there are no childrent and it's only text inside.
So the two scenarios are:
<div id="wrap">text1</div>
and
<div id="wrap"><b>text1</b><b>text2</b></div>
So In both cases I want to get back "text1"
I know how to do it with 2 different queries but I am trying to unite them into one
$("#wrap :first-child").text()
$("#wrap").text()
$("#wrap :first-child").text() || $("#wrap").text()
As jquery selector expressions give results in document order, the expressions can be combined.
$('#wrap :first-child, #wrap').filter(':last').text()

Categories

Resources