1

I want to use jQuery to select every element that has a certain text string in it, but not the parents of that element. How do I do this? I have no control whatsoever over the HTML code, but here is an example:

<body>
<div>
<p>This is a paragraph and <a>this is not</a>.</p>
Here we have a div.
</div>
</body>

If I use the word "this" as my match word, I want jQuery to provide me with a set containing the <a> and the <p>, but not the <div> or the <body>.

Again, I have no control AT ALL over the HTML!

Thanks!

** Clarification: I do want the parent of the element if the parent ALSO has a "this" in its immediate text. Thus, I want the <a> AND the <p>.

gcdev
  • 1,406
  • 3
  • 17
  • 30
  • http://stackoverflow.com/questions/926580/find-text-string-using-jquery This might help ;) – Robin Jul 17 '11 at 00:49
  • :contains will return the body and div as well as the p and the a. I just want the p and the a. – gcdev Jul 17 '11 at 01:30

2 Answers2

1

Update::

Here is what I came up with: jsfiddle

var myArray = $('*:contains("this")','body').filter(function(){
    if($(this).contents().filter(function(){
        return(this.nodeType == 3);
    }).text().indexOf('this')===-1){
        return false;
    }
    return true;
});


$.each(myArray,function(){
   console.log(this.nodeName); 
});

Starts similar to the link posted by Robin, but it forces to only search in the context of body elements - this keeps your scripts safe if they are not inline.

The next part is a filter that checks to see if the current element direct text nodes contain the text.

This is a bit convoluted, but to walk through it:

.contents() - docs - gets the immediate nodes

.filter() - docs - we want to only test on test nodes, so we filter them out

this.nodeType - w3 spec - check to see if its a text node

.test() - docs - gets a string of the text nodes.

.indexOf() - check that string for our string

Note I did the :contains() at the top and in the second filter, the first isn't needed per say but I think the initial test should reduce the number of deeper tests and speed it up slightly.

WSkid
  • 2,736
  • 2
  • 22
  • 26
  • I don't want to exclude nodes with children. That would kick the p out of the set. I want the p because it has a "this" in it. But I also want the a, because it also has a "this" in it. – gcdev Jul 17 '11 at 01:38
  • Updated with something that keys off the actual child text nodes and should be better suited to your requirements – WSkid Jul 17 '11 at 02:14
  • It still only finds the anchor tag, not the paragraph tag as well. – gcdev Jul 17 '11 at 19:53
  • Figured it out. In my sample, 'this' was capitalized once and not the other time. I changed one line of your solution WSkid: .text().toLowerCase().indexOf('this')===-1) – gcdev Jul 17 '11 at 23:33
0

Here's my solution with pure JS.

Code:

function findElmsWithWord(word, elm, found){
    if (elm.nodeType === 3 && elm.data.indexOf(word) !== -1)
        found.push(elm.parentNode);
    else
        for (var i = 0; i < elm.childNodes.length; i++)
            findElmsWithWord(word, elm.childNodes[i], found);
}

var elms = []; findElmsWithWord('this', document.body, elms); console.log(elms);

It recursively walks the dom until it finds the text nodes that contain the word in question. And then adds the text node's parent as a result.

airportyh
  • 21,948
  • 13
  • 58
  • 72
  • This solution is only finding the anchor tag. I am looking for a way to get both the anchor and the paragraph (well, any element that 'owns' the word, which in this case is the p and the a). – gcdev Jul 17 '11 at 19:59
  • It *does* do what you want. Did you try running the fiddle? – airportyh Jul 18 '11 at 01:02
  • No sir, but I tested it in FireFox w/ notepad. Maybe the problem was the capitalization, like WSkid's solution above. I've already marked his as the answer though (once I figured out the capitalization thing) -- since he did provide a jQuery solution, which is what I was originally seeking. – gcdev Jul 18 '11 at 12:06