views:

57

answers:

2

I am trying to use the text attribute as a selector, but I can't quite grasp the behaviour, would really appreciate if someone could explain. For example given <span class="span_class"><a class="a_class">text</a></span>, $('a.a_class').text() gives "text" as expected. However $('a.a_class[text]') wouldn't match any elements, and neither would $('span.span_class > a.a_class[text]'), but $('span.span_class* > a.a_class[text]') would (although not in IE). The only workaround I can think of for IE, is loop through all anchors contained in a span, use .text() on each and match it against a certain criteria, but it seems slower than using in-built selectors. Anyone have better ideas?

+2  A: 

This is because 'text' in this case is not an attribute. It is the content of the element.

You're looking for the :contains() selector:

$('a.a_class:contains(text)');

http://api.jquery.com/contains-selector/

Keep in mind that this selector will match any part of the string. contains(foo) will match "foo bar" as well.

If you want an exact match of the entire text string, you could use filter()

$('a.a_class').filter(function() {
    return $(this).text() == "text";
});

EDIT:

To find elements whose content starts with a value, you could use a regular expression inside the filter():

$('a.a_class').filter(function() {
    return $(this).text().indexOf( "tex" ) >= 0;
});

EDIT: Updated to use indexOf() instead of regex as recommended by @Nick.

patrick dw
Hmm ok. What I was looking for was "Starts with" though, and `$('span.span_class* > a.a_class[text^="tex"]')` was working great, until I tested it with IE.
Shagglez
@Shagglez - I didn't realize that would work at all. I guess I'd use the `filter()` option with regex to figure out if the text start with "tex".
patrick dw
@Shagglez - You can use what @patrick has, just replace `return $(this).text() == "text";` with `return $(this).text().indexOf("text") ===0;` for a "start-with" check.
Nick Craver
Unless you *need* a regular expression, use `.indexOf()`, it's *much* faster, and when you're talking about selectors, especially on potentially large numbers of elements, speed matters.
Nick Craver
@Nick - Thanks for the pointer. :o)
patrick dw
+2  A: 

what about using a custom selector

$(document).ready(function(){
  $.extend($.expr[':'], {
    notext: function(elem, i, attr){
      return( $(elem).text() === "" );
    }
  });        
});

Synopsis

$('span:notext').remove();

you might even want to create a selector that handles Regular Expressions like

$.extend($.expr[':'], {
   'content': function(elem, i, attr){      
     return( RegExp(attr[3]).test($(elem).text()) );
   }
});

Synopsis

$('span:content(^api_)').remove();

would select and remove all spans which text begins with api_

jAndy
No need for a `document.ready` wrapper :)
Nick Craver
I'll leave the same comment here: Unless you *need* a regular expression, use `.indexOf()`, it's *much* faster, and when you're talking about selectors, especially on potentially large numbers of elements, speed matters.
Nick Craver
Perfect, exactly what I was looking for :). Thanks.
Shagglez
Yep, I adapted it to use indexOf as well. Thanks for help everyone.
Shagglez
@Nick: I wanted to create it like so, a selector which uses regular expressions.
jAndy
Probably better to use `$.text(elem)` instead of `$(elem).text()` -- the former is much faster because it avoids constructing a new jQ instance.
J-P
@J-P - `$.text()` operates on an array, it'd actually be `$.text([this])`, but good point on performance :)
Nick Craver
@Nick, ah, thanks, forgot about that :)
J-P