10

is there a straightforward method for searching within a div for a specific string and replacing it with another? I cannot use .replaceWith alone because there are other elements within the div I need to preserve. I've tried various javascript methods found here to no avail.

So something like:

$('#foo').find('this string').replaceWith('this other string');

for:

<div id="foo"><div id="child">Other Element</div>this string</div>

Thanks.

pac
  • 164
  • 2
  • 2
  • 9
  • see http://stackoverflow.com/questions/2349138/jquery-find-and-replace-text-without-element-id/2349208#2349208 – Anurag May 12 '11 at 20:04

6 Answers6

9

Try this:

var foo = $('#foo').html();

foo = foo.replace('this string', 'this other string');

$('#foo').html(foo);

Fiddle: http://jsfiddle.net/maniator/w9GzF/

Naftali
  • 144,921
  • 39
  • 244
  • 303
  • "there are other elements within the div I need to preserve" -- this would not be suitable – Gary Green May 12 '11 at 19:59
  • 1
    This doesn't work if you have multiple occurrences of 'this string'. – Code Maverick May 12 '11 at 20:02
  • 2
    setting the `html(..)` like that will re-create DOM elements, meaning you would lose out on any previously attached data or events on those elements. – Anurag May 12 '11 at 20:03
  • 1
    @Anurag i see no other way to do it. to preserve the handlers, i would say to use `live()` – Naftali May 12 '11 at 20:05
  • @Neal I believe HTML rewriting is harmful. – Šime Vidas May 12 '11 at 20:05
  • @pac, remember to select an `accepted answer` when you can :-D – Naftali May 12 '11 at 20:05
  • 1
    Yea, you could definitely use `live()` or `delegate()`. I've done this exact scenario and it's what I had to do. – Code Maverick May 12 '11 at 20:06
  • @Neal - the [linked answer](http://stackoverflow.com/questions/2349138/jquery-find-and-replace-text-without-element-id/2349208#2349208) shows one way to do it. Here's an [example](http://jsfiddle.net/A2WAb/2/). – Anurag May 12 '11 at 20:10
  • @Sime, yes, that was my original thought, but that could also screw up the html, see (deleted answer) – Naftali May 12 '11 at 20:10
  • @Neal That answer is doing it wrong. Retrieving the text content with `text()` will remove all child elements. That's not what I said which is: walk the DOM and execute `replace()` on every Text node. – Šime Vidas May 12 '11 at 20:16
9

This replaces all occurrences:

var $foo = $('#foo'),
    fooHtml = $foo.html();

$foo.html(fooHtml.replace(/this string/g, 'this other string'));
Code Maverick
  • 20,171
  • 12
  • 62
  • 114
3

Just using html().replace() with match all results element attribute or tag name.

I face this issue also, my solution is similar to findAndReplace() function from http://james.padolsey.com/javascript/find-and-replace-text-with-javascript/ but using regular expression to get all textNode and search in each of them.

function epubSearch(query) {
    var d = document.getElementsByTagName("body")[0];
    var re = new RegExp(query, "gi");//pattern for keyword
    var re0 = new RegExp("[>][^><]*[><]", "gi");//pattern to get textnode

    d.innerHTML = d.innerHTML.replace(re0, function (text) {
        // with each textNode, looking for keyword
        return text.replace(re, "<span class=\"search-result\" style=\"background-color:red;\">$&</span>");
    });
}
AnVo
  • 111
  • 6
2

Here's a jQuery plugin I just wrote that provides safeReplace for collections.

(function($){

$.fn.safeReplace = function ( find, replacement ) {

    return this.each(function(index, elem) {

        var
            queue = [elem],
            node,
            i;

        while (queue.length) {

            node = queue.shift();

            if (node.nodeType === 1) {
                i = node.childNodes.length;
                while (i--) {
                    queue[queue.length] = node.childNodes[i];
                }
            } else if (node.nodeType === 3) {
                node.nodeValue = node.nodeValue.replace( find, replacement );
            }
        }

    });
};

})(jQuery);

And here's how you use it:

$('#foo').safeReplace( /this string/g, 'something else' );

I've only tested in FF 4, and only on the sample HTML input - more testing is recommended.

Hope this helps!

jimbo
  • 11,004
  • 6
  • 29
  • 46
1

What's wrong with String.replace();?

e.g.

$("#div").html($("#div").html().replace("search string", "replace string"));

Or Exploded:

var $divElement = $("#div");         //Find the div to perform replace on
var divContent = $divElement.html(); //Get the div's content
divContent = divContent.replace("search string", "replace string"); //Perform replace
$divElement.html(divContent);        //Replace contents of div element.
Karl Nicoll
  • 16,090
  • 3
  • 51
  • 65
0

This one works as many times as your term appears and will not kill any of the important things that shouldn't be changed (stored in the excludes array).

usage: findAndReplace('dog','cat', document.getElementById('content'));

/* js find andreplace Based on http://james.padolsey.com/javascript/find-and-replace-text-with-javascript/ */

function findAndReplace(searchText, replacement, searchNode) {
if (!searchText || typeof replacement === 'undefined') {
    return;
}
var regex = typeof searchText === 'string' ?
            new RegExp(searchText, 'g') : searchText,
    childNodes = (searchNode || document.body).childNodes,
    cnLength = childNodes.length,
    excludes = ['html','head','style','link','meta','script','object','iframe'];
while (cnLength--) {
    var currentNode = childNodes[cnLength];
    if (currentNode.nodeType === 1 &&
      excludes.indexOf(currentNode.nodeName.toLowerCase() + ',') === -1) {
      arguments.callee(searchText, replacement, currentNode);
    }
    if (currentNode.nodeType !== 3 || !regex.test(currentNode.data) ) {
        continue;
    }
    var parent = currentNode.parentNode,
        frag = (function(){
            var html = currentNode.data.replace(regex, replacement),
                wrap = document.createElement('div'),
                frag = document.createDocumentFragment();
            wrap.innerHTML = html;
            while (wrap.firstChild) {
                frag.appendChild(wrap.firstChild);
            }
            return frag;
        })();
    parent.insertBefore(frag, currentNode);
    parent.removeChild(currentNode);
}
}
marblegravy
  • 212
  • 2
  • 9