149

Is there a case insensitive version of the :contains jQuery selector or should I do the work manually by looping over all elements and comparing their .text() to my string?

BoltClock
  • 700,868
  • 160
  • 1,392
  • 1,356
Pat
  • 36,282
  • 18
  • 72
  • 87

12 Answers12

128

What I ended up doing for jQuery 1.2 is :

jQuery.extend(
    jQuery.expr[':'], { 
        Contains : "jQuery(a).text().toUpperCase().indexOf(m[3].toUpperCase())>=0" 
});

This will extend jquery to have a :Contains selector that is case insensitive, the :contains selector remains unchanged.

Edit: For jQuery 1.3 (thanks @user95227) and later you need

jQuery.expr[':'].Contains = function(a,i,m){
     return jQuery(a).text().toUpperCase().indexOf(m[3].toUpperCase())>=0;
};

Edit: Apparently accessing the DOM directly by using

(a.textContent || a.innerText || "") 

instead of

jQuery(a).text()

In the previous expression speeds it up considerably so try at your own risk if speed is an issue. (see @John 's question)

Latest edit: For jQuery 1.8 it should be:

jQuery.expr[":"].Contains = jQuery.expr.createPseudo(function(arg) {
    return function( elem ) {
        return jQuery(elem).text().toUpperCase().indexOf(arg.toUpperCase()) >= 0;
    };
});
Community
  • 1
  • 1
Pat
  • 36,282
  • 18
  • 72
  • 87
  • Just wanted to let folks know that the solution as described by @Pat and others for jQuery 1.3 also works for 1.4.3. – Jim Ade Nov 03 '10 at 17:54
  • Link to @John's question/answer since the link here was deleted: http://stackoverflow.com/questions/1407434/is-there-any-way-to-speed-up-this-solution-for-a-case-insensitive-jquery-contai – Mottie Jan 30 '12 at 01:53
  • This doesn't work for jQuery 1.8. See seagullJS's answer below for an updated version -- http://stackoverflow.com/a/12113443/560114 – Matt Browne Sep 27 '12 at 00:11
108

To make it optionally case insensitive: http://bugs.jquery.com/ticket/278

$.extend($.expr[':'], {
  'containsi': function(elem, i, match, array)
  {
    return (elem.textContent || elem.innerText || '').toLowerCase()
    .indexOf((match[3] || "").toLowerCase()) >= 0;
  }
});

then use :containsi instead of :contains

montrealmike
  • 11,433
  • 10
  • 64
  • 86
41

As of jQuery 1.3, this method is deprecated. To get this to work it needs to be defined as a function:

jQuery.expr[':'].Contains = function(a,i,m){
    return jQuery(a).text().toUpperCase().indexOf(m[3].toUpperCase())>=0;
};
user95227
  • 520
  • 4
  • 7
39

If someone (like me) is interested what do a and m[3] mean in Contains definition.


KEY/LEGEND: Params made available by jQuery for use in the selector definitions:

r = jQuery array of elements being scrutinised. (eg: r.length = Number of elements)

i = index of element currently under scrutiny, within array r.

a = element currently under scrutiny. Selector statement must return true to include it in its matched results.

m[2] = nodeName or * that we a looking for (left of colon).

m[3] = param passed into the :selector(param). Typically an index number, as in :nth-of-type(5), or a string, as in :color(blue).

Alexander Prokofyev
  • 33,874
  • 33
  • 95
  • 118
32

In jQuery 1.8 you will need to use

jQuery.expr[":"].icontains = jQuery.expr.createPseudo(function (arg) {                                                                                                                                                                
    return function (elem) {                                                            
        return jQuery(elem).text().toUpperCase().indexOf(arg.toUpperCase()) >= 0;        
    };                                                                                  
});
seagullJS
  • 529
  • 1
  • 5
  • 8
15

A variation that seems to perform slightly faster and that also allows regular expressions is:

jQuery.extend (
    jQuery.expr[':'].containsCI = function (a, i, m) {
        //-- faster than jQuery(a).text()
        var sText   = (a.textContent || a.innerText || "");     
        var zRegExp = new RegExp (m[3], 'i');
        return zRegExp.test (sText);
    }
);



Not only is this case-insensitive, but it allows powerful searches like:

  • $("p:containsCI('\\bup\\b')") (Matches "Up" or "up", but not "upper", "wakeup", etc.)
  • $("p:containsCI('(?:Red|Blue) state')") (Matches "red state" or "blue state", but not "up state", etc.)
  • $("p:containsCI('^\\s*Stocks?')") (Matches "stock" or "stocks", but only at the start of the paragraph (ignoring any leading whitespace).)
Brock Adams
  • 90,639
  • 22
  • 233
  • 295
12

May be late.... but,

I'd prefer to go this way..

$.extend($.expr[":"], {
"MyCaseInsensitiveContains": function(elem, i, match, array) {
return (elem.textContent || elem.innerText || "").toLowerCase().indexOf((match[3] || "").toLowerCase()) >= 0;
}
});

This way, you DO NOT tamper with jQuery's NATIVE '.contains'... You may need the default one later...if tampered with, you might find yourself back to stackOverFlow...

ErickBest
  • 4,586
  • 5
  • 31
  • 43
6
jQuery.expr[':'].contains = function(a,i,m){
    return jQuery(a).text().toUpperCase().indexOf(m[3].toUpperCase())>=0;
};

The update code works great in 1.3, but "contains" should be lower case on the first letter unlike the previous example.

5

Refer below to use ":contains" to find text ignoring its case sensitivity from an HTML code,

 $.expr[":"].contains = $.expr.createPseudo(function(arg) {
            return function( elem ) {
                return $(elem).text().toUpperCase().indexOf(arg.toUpperCase()) >= 0;
            };
        });
        $("#searchTextBox").keypress(function() {
          if($("#searchTextBox").val().length > 0){
            $(".rows").css("display","none");
            var userSerarchField = $("#searchTextBox").val();
            $(".rows:contains('"+ userSerarchField +"')").css("display","block");
          } else {
            $(".rows").css("display","block");
          }              
        });

You can also use this link to find case ignoring code based on your jquery version, Make jQuery :contains Case-Insensitive

Umesh Patil
  • 4,668
  • 32
  • 24
3

A faster version using regular expressions.

$.expr[':'].icontains = function(el, i, m) { // checks for substring (case insensitive)
    var search = m[3];
    if (!search) return false;

    var pattern = new RegExp(search, 'i');
    return pattern.test($(el).text());
};
Howard
  • 3,648
  • 13
  • 58
  • 86
0

I had a similar problem with the following not working...

// This doesn't catch flac or Flac
$('div.story span.Quality:not(:contains("FLAC"))').css("background-color", 'yellow');

This works and without the need for an extension

$('div.story span.Quality:not([data*="flac"])').css("background-color", 'yellow');

This works too, but probably falls into the "manually looping" category....

$('div.story span.Quality').contents().filter(function()
{
  return !/flac/i.test(this.nodeValue);
}).parent().css("background-color", 'yellow');
shao.lo
  • 4,387
  • 2
  • 33
  • 47
0

New a variable I give it name subString and put string you want to search in some elements text. Then using Jquery selector select elements you need like my example $("elementsYouNeed") and filter by .filter(). In the .filter() it will compare each elements in $("elementsYouNeed") with the function.

In the function i using .toLowerCase() for element text also subString that can avoid case sensitive condition and check if there is a subString in it. After that the .filter() method constructs a new jQuery object from a subset of the matching elements.

Now you can get the match elements in matchObjects and do whatever you want.

var subString ="string you want to match".toLowerCase();

var matchObjects = $("elementsYouNeed").filter(function () {return $(this).text().toLowerCase().indexOf(subString) > -1;});
劉鎮瑲
  • 517
  • 9
  • 20