8

I try to find and replace text (using jQuery). Actually I'm trying to add a span element around the text. I should also be able to remove the span again without losing the text inside.

For example, let's say I have the following situation to start with:

<span>This is a span element</span>

And I want to be able to do this dynamically using jQuery/JavaScript:

<span>This is a <span class="marked">span</span> element</span>

I should also be able to remove the span.marked and get back to the first result.

The problem however is that I want to do this on all text inside a container with multiple children and subchildren and so on.

The code I got so far will do the following and that is not what I want:

<<span class="marked">span</span>>This is a <span class="marked">span</<span class="marked">span</span> element</span>

I want to do this for ALL text on the page, not just the first it finds.

EDIT: my code so far for doing this:

var re = new RegExp(word, 'g');
$('.container').html($('.container').html().replace(re, '<span class="marked">' + word + '</span>'));

word is a string with the text to wrap spans around.

5
  • 6
    Show you JS code. Commented May 20, 2014 at 12:24
  • 2
    in your last code line i see dubbel << and >> round your first span="marked". Is this a typemistake or... ? Commented May 20, 2014 at 12:27
  • 2
    you can search for " span " word with space before and after instead of just "span". so your span element will not be replaced. Commented May 20, 2014 at 12:27
  • 2
    @VDesign that's the problem he's having. His code wraps the "span" inside his existing <span> tags with <span class="marked">..... Commented May 20, 2014 at 12:32
  • I have a solution that works. See my answer below. Commented May 20, 2014 at 13:39

7 Answers 7

11

To wrap a search string in html you can use something like this:

$('span:contains("word")').html().replace('word', '<span class="marked">word</span>');

and to remove it, you can use something like this:

$('span:contains("word")').html().replace('<span class="marked">word</span>', 'word');

Yes this is a pretty crude way of doing it but it should work.

EDIT: as pointed out by @user3558931, the word needs to be a variable.

To wrap a search string in html you can use something like this:

$('span:contains("' + str + '")').html().replace(str, '<span class="marked">' + str + '</span>');

and to remove it, you can use something like this:

$('span:contains("' + str + '")').html().replace('<span class="marked">' + str + '</span>', str);

EDIT: A glitch in the above code, see the fixed code in this fiddle: http://jsfiddle.net/thePav/7TNk6/21/

Sign up to request clarification or add additional context in comments.

6 Comments

This will not work. Per PO word is a variable, not a string.
Apologies, I shall update the code, I think the original question was updated after I had answered.
This will only work on span tags? I'm trying to do so for all nested tags within a container. I tried your code like $('*:contains(.... but that didn't seem to work.
Yep, that piece of code is directed at span tags. To do this with selector classes you could use something like $('.container').html()
Apologies, there was a glitch in that code. First you would have to store the data into a variable and then apply it. Check out this fiddle: jsfiddle.net/thePav/7TNk6/21
|
6
$('.container p').each(function() {
    var text = $(this).text();
    $(this).html(text.replace('word', '<strong><span class="accordion">word </span></strong>')); 
});

Comments

2

Don't use a regular expression. Use DOM traversal, which will be much more reliable, faster and less destructive (event handlers are not destroyed, for example).

See https://stackoverflow.com/a/10618517/96100 for a simple example.

Alternatively, you could use the following:

http://james.padolsey.com/javascript/replacing-text-in-the-dom-solved/

This doesn't cover removing the spans afterwards but that is a reasonably simple matter. Something like the following (untested):

function replaceWithOwnChildren(el){
    var parent = el.parentNode;
    while (el.hasChildNodes()) {
        parent.insertBefore(el.firstChild, el);
    }
    parent.removeChild(el);
}

// Create a non-live standard array of spans
var spans = [].slice.call(document.getElementsByTagName("span"), 0);
for (var i = 0, len = spans.length; i < len; ++i) {
    if (spans[i].className == "marked") {
        replaceWithOwnChildren(spans[i]);
    }
}

// Glue together any adjacent text nodes
document.normalize();

Comments

1

I believe the regular expression needs to be adjusted so it does not pick <span or any other HTML tag for that matter. I would like to suggest the RegExp:

var re = new RegExp('[^<\\/](' + word + ')', 'g');

And the replacement:

$('.container').each(function() {
    $(this).html( $(this).html().replace( re, ' <span class="marked">$1</span>' ) );
});

And can be reversed by using the code (Click button in demo below):

$('button.undo').on( 'click', function() {
    $('.container').find( 'span.marked' ).each(function() {
        $(this).replaceWith( word );
    });
});

JS FIDDLE DEMO

OTHER DEMO

Comments

1
var mark = function(word){
    return function(){
        this.innerHTML = this.innerHTML.replace(word,'' + word + '');
    }
};
$('span').each(mark('span'));

1 Comment

My HTML is a bit more complex: jsfiddle.net/TCvg7/2 <-- that is just an example, the real version has even more tags and nested tags.
0

Try using following:

$('.container').forEach(function(){ 
    $(this).html().... 
})

If that is your problem that is. Otherwise, please clarify, what exactly isn't working as it is supposed to?

Comments

0
var span = document.getElementsByTagName("span")[0];
span.innerHTML = span.innerHTML.replace(/span/g, "<span class=\"marked\">span</span>");

http://jsfiddle.net/7TNk6/1/

5 Comments

It's not only span element, it is the whole page I'm trying to modify. Like this: jsfiddle.net/7TNk6/3
Alright, well you seem to have your own solution derived from mine, then. What's wrong about yours?
It replaces html tags as well. It should only replace text BY html tags with text.
Try this simple fix: jsfiddle.net/7TNk6/17 All I did was add a space before the word in the replace, and in the html that replaces it. It's not elegant, but it works.
Will give problems when I need to mark the first word of an element. But it's getting closer to what I need.

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.