Algorithm
Algorithm

Reputation: 329

How to select a part of string?

How to select a part of string?

My code (or example):

<div>some text</div>

$(function(){
    $('div').each(function(){
        $(this).text($(this).html().replace(/text/, '<span style="color: none">$1<\/span>'));
    });
});

I tried this method, but in this case is selected all context too:

$(function(){
    $('div:contains("text")').css('color','red');
});

I try to get like this:

<div><span style="color: red">text</span></div>

Upvotes: 1

Views: 1030

Answers (4)

Tim Down
Tim Down

Reputation: 324507

The general practice of interacting with the DOM as strings of HTML using innerHTML has many serious drawbacks:

  • Event handlers are removed or replaced
  • Opens the possibility of script inject attacks
  • Doesn't work in XHTML

It also encourages lazy thinking. In this particular instance, you're matching against the string "text" within the HTML with the assumption that any occurrence of the string must be within a text node. This is patently not a valid assumption: the string could appear in a title or alt attribute, for example.

Use DOM methods instead. This will get round all the problems. The following will use only DOM methods to surround every match for regex in every text node that is a descendant of a <div> element:

$(function() {
    var regex = /text/;

    function getTextNodes(node) {
        if (node.nodeType == 3) {
            return [node];
        } else {
            var textNodes = [];
            for (var n = node.firstChild; n; n = n.nextSibling) {
                textNodes = textNodes.concat(getTextNodes(n));
            }
            return textNodes;
        }
    }

    $('div').each(function() {
        $.each(getTextNodes(this), function() {
            var textNode = this, parent = this.parentNode;
            var result, span, matchedTextNode, matchLength;
            while ( textNode && (result = regex.exec(textNode.data)) ) {
                matchedTextNode = textNode.splitText(result.index);
                matchLength = result[0].length;
                textNode = (matchedTextNode.length > matchLength) ?
                    matchedTextNode.splitText(matchLength) : null;
                span = document.createElement("span");
                span.style.color = "red";
                span.appendChild(matchedTextNode);
                parent.insertBefore(span, textNode);
            }
        });
    });
});

Upvotes: 0

Peter Kruithof
Peter Kruithof

Reputation: 10764

$(function(){
    $('div:contains("text")').each(function() {
        $(this).html($(this).html().replace(/(text)/g, '<span style="color:red;">\$1</span>'));
    });
});

I've updated your fiddle: http://jsfiddle.net/nMzTw/15/

Upvotes: 0

Šime Vidas
Šime Vidas

Reputation: 185893

$('div').each(function () {
    $(this).html(function (i, v) {
        return v.replace(/foo/g, '<span style="color: red">$&<\/span>');
    });
});

Upvotes: 2

T.J. Crowder
T.J. Crowder

Reputation: 1074148

What are you actually trying to do? What you're doing at the moment is taking the HTML of each matching DIV, wrapping a span around the word "text" if it appears (literally the word "text") and then setting that as the text of the element (and so you'll see the HTML markup on the page).

If you really want to do something with the actual word "text", you probably meant to use html rather than text in your first function call:

$('div').each(function(){
    $(this).html($(this).html().replace(/text/, '<span style="color: none">$1<\/span>'));
         // ^-- here
}

But if you're trying to wrap a span around the text of the div, you can use wrap to do that:

$('div').wrap('<span style="color: none"/>');

Like this: http://jsbin.com/ucopo3 (in that example, I've used "color: blue" rather than "color: none", but you get the idea).

Upvotes: 1

Related Questions