How to change text inside span with jQuery, leaving other span contained nodes intact?

10,956

Solution 1

Try something like:

$('a.changeme').on('click', function() {
  $(this).closest('.target').contents().not(this).eq(0).replaceWith('Do it again ');
});

demo: http://jsfiddle.net/eEMGz/

ref: http://api.jquery.com/contents/

Update:

I guess I read your question wrong, and you're trying to replace the text if it's already there and inject it otherwise. For this, try:

$('a.changeme').on('click', function() {
  var
    $tmp = $(this).closest('.target').contents().not(this).eq(0),
    dia = document.createTextNode('Do it again ');

  $tmp.length > 0 ? $tmp.replaceWith(dia) : $(dia).insertBefore(this);
});

​Demo: http://jsfiddle.net/eEMGz/3/

Solution 2

You can try this.

var $textNode, $parent;
$('.changeme').on('click', function(){
    $parent = $(this).parent(); 
    $textNode= $parent.contents().filter(function() {
            return this.nodeType == 3;
    });
    if($textNode.length){
        $textNode.replaceWith('Content changed')
    }
    else{
        $parent.prepend('New content');
    }
});

Working demo - http://jsfiddle.net/ShankarSangoli/yx5Ju/8/

Solution 3

You can use .contents():

//set the new text to replace the old text
var newText = 'New Text';

//bind `click` event handler to the `.changeme` elements
$('.changeme').on('click', function () {

    //iterate over the nodes in this `<span>` element
    $.each($(this).parent().contents(), function () {

        //if the type of this node is undefined then it's a text node and we want to replace it
        if (typeof this.tagName == 'undefined') {

            //to replace the node we can use `.replaceWith()`
            $(this).replaceWith(newText);
        }
    });
});​

Here is a demo: http://jsfiddle.net/jasper/PURHA/1/

Some docs for ya:

Update

var newText = 'New Text';
$('a').on('click', function () {
    $.each($(this).parent().contents(), function () {
        if (typeof this.tagName == 'undefined') {

            //instead of replacing this node with the replacement string, just replace it with a blank string
            $(this).replaceWith('');
        }
    });

    //then add the replacement string to the `<span>` element regardless of it's initial state
    $(this).parent().prepend(newText);
});​

Demo: http://jsfiddle.net/jasper/PURHA/2/

Solution 4

You step out of jQuery because it doesn't help you to deal with text nodes. The following will remove the first child of every <span> element with class "target" if and only if it exists and is a text node.

Demo: http://jsfiddle.net/yx5Ju/11/

Code:

$('span.target').each(function() {
    var firstChild = this.firstChild;
    if (firstChild && firstChild.nodeType == 3) {
        firstChild.data = "Do it again";
    }
});
Share:
10,956
András Szepesházi
Author by

András Szepesházi

Updated on June 09, 2022

Comments

  • András Szepesházi
    András Szepesházi almost 2 years

    I have the following HTML snippet:

    <span class="target">Change me <a class="changeme" href="#">now</a></span>
    

    I'd like to change the text node (i.e. "Change me ") inside the span from jQuery, while leaving the nested <a> tag with all attributes etc. intact. My initial huch was to use .text(...) on the span node, but as it turns out this will replace the whole inner part with the passed textual content.

    I solved this with first cloning the <a> tag, then setting the new text content of <span> (which will remove the original <a> tag), and finally appending the cloned <a> tag to my <span>. This works, but feels such an overkill for a simple task like this. Btw. I can't guarantee that there will be an initial text node inside the span - it might be empty, just like:

    <span class="target"><a class="changeme" href="#">now</a></span>
    

    I did a jsfiddle too. So, what would be the neat way to do this?

  • András Szepesházi
    András Szepesházi about 12 years
    "Btw. I can't guarantee that there will be an initial text node inside the span - it might be empty" this test case fails.
  • Jasper
    Jasper about 12 years
    @AndrásSzepesházi I didn't realize you wanted to add the new string to empty containers as well. I updated my answer, here's a demo: jsfiddle.net/jasper/PURHA/2
  • András Szepesházi
    András Szepesházi about 12 years
    you forgot to update your fiddle, but the code quoted above works nicely for both cases (i.e. having / not having) initial text.
  • András Szepesházi
    András Szepesházi about 12 years
    "Btw. I can't guarantee that there will be an initial text node inside the span - it might be empty" this test case fails. Otherwise cool.
  • András Szepesházi
    András Szepesházi about 12 years
    "Btw. I can't guarantee that there will be an initial text node inside the span - it might be empty" this test case fails. Otherwise cool.
  • András Szepesházi
    András Szepesházi about 12 years
    "Btw. I can't guarantee that there will be an initial text node inside the span - it might be empty" this test case fails. Otherwise cool.
  • Jasper
    Jasper about 12 years
    One strange behavior is if there are text nodes on both sides of the <a> element they will both be replaced with the new text: jsfiddle.net/jasper/yx5Ju/9
  • ShankarSangoli
    ShankarSangoli about 12 years
    @Jasper - If that is going to be the case then it can be handled in the code. OP will know it better if such condition exists.
  • Code Junkie
    Code Junkie about 12 years
    It seems like this might be a good place to extend jQuery higher up in the code, just to keep the working code clean; do you think so?
  • András Szepesházi
    András Szepesházi about 12 years
    Thanks! With a slight change this works for both cases I needed (both text replace and insert modes), jsfiddle.net/yx5Ju/12
  • Yoshi
    Yoshi about 12 years
    @CodeJunkie I'm not sure. If this was just over and over again, then a plugin might be ok, but otherwise I'd stick without extending jquery for such little tasks.