3

I need to select all elements that contain multiple classes. The class names don't matter, I just need to select any elements with two or more.

What would the jQuery selector for that look like?

BoltClock
  • 700,868
  • 160
  • 1,392
  • 1,356
CaffGeek
  • 21,856
  • 17
  • 100
  • 184
  • Similar but for pure CSS: [Use CSS to target any element that has ANY two classes on it?](http://stackoverflow.com/questions/6847584/use-css-to-target-any-element-that-has-any-two-classes-on-it) (my answer works as a jQuery selector too) – BoltClock Oct 04 '11 at 18:55

5 Answers5

8

This should select all elements with more than two classes.

$('*').filter(function() {
  return this.className.trim().split(/\s+/).length > 1;
}).foo('bar');
Blender
  • 289,723
  • 53
  • 439
  • 496
  • 1
    Touche, didn't think to go this route. +1 for showing a different interpretation. – Brad Christie Oct 04 '11 at 18:58
  • Not to be mean, but this isn't actually the correct solution because elements that have a single class but have some spaces in the class attribute may get incorrectly selected as well, as I explained below in my answer. Here's an example of this: http://jsfiddle.net/udBZy/3/ Also, $('*') is unnecessarily inefficient. – maxedison Oct 04 '11 at 21:04
  • @maxedison: thanks, I didn't actually run the code. As for the efficiency, you could go even further and define a scope that's a bit more specific than `*`. I just chose the most broad. – Blender Oct 04 '11 at 21:44
  • Why do you use a regex for .split()? – maxedison Oct 05 '11 at 12:30
  • @maxedison: If he split by a single space, "foo[space][space]bar" would be split into three components, "foo", "" and "bar". The regex is there to clear any contiguous spaces. – BoltClock Oct 05 '11 at 15:13
3
$('[class*=" "]')

Returns all tags with a space in the class attribute.

Elliot Nelson
  • 11,371
  • 3
  • 30
  • 44
2

A different understanding leads me to a better solution (my apologies for jumping to a conclusion):

Demo

(function($){
    $.expr[':'].classes = function(o,i,m,s){
        var c = o.className.match(/\s*(.*)\s*/)[0].split(/\s+/).length;

        // Hard [fixed] limit
        // :classes(N)
        if (/^\d+$/.test(m[3])) {
            var n = parseInt(m[3], 10);
            return o.className.split(/\s+/).length == n;
        }

        // Expression:
        // :classes(>N)    :classes(>=N)
        // :classes(>N)    :classes(<=N)
        else if (/^[<>]=?\d+$/.test(m[3])) {
            var e = m[3].match(/^[><]=?/)[0],
                n = m[3].match(/\d+$/)[0];
            switch (e){
                case '<':
                    return c < n;
                case '<=':
                    return c <= n;
                case '>':
                    return c > n;
                case '>=':
                    return c >= n;
            }
        }

        // Range
        // :classes(4-6)
        else if (/^\d+\-\d+$/.test(m[3])) {
            var ln = parseInt(m[3].match(/^(\d+)/)[0], 10),
                hn = parseInt(m[3].match(/(\d+)$/)[0], 10);
            return ln <= c && c <= hn;
        }

        // all else fails
        return false;
    };
})(jQuery);

Updated Added a bit more flexibility with regards to the argument you can supply. Now you have the following options (replacing N & M with numbers):

  • :classes(N)
    Finds elements with exactly N classes
  • :classes(<=N)
    Finds elements with N or fewer classes
  • :classes(<N)
    Finds elements with fewer than N classes
  • :classes(>=N)
    Finds elements with N or more classes
  • :classes(>N)
    Finds elements with more than N classes
  • :classes(N-M)
    Finds elements whose class count falls between N and M
Brad Christie
  • 100,477
  • 16
  • 156
  • 200
1

The following code will first select all elements with a space in the class attribute. We could just do $('*') as Blender suggests, but that's less efficient because it initially selects ALL elements on the page, rather than just those that are viable candidates (i.e., have a space in the class name).

It also takes into consideration those cases where there is just one class, but the class attribute has a space in it (this is done by using jQuery's $.trim() method on the class attribute prior to splitting it). Blender's doesn't solve this kind of situation.

$(function(){
    var div = $('div[class*=" "]').filter(function(){
        var clsArray = $.trim(this.className.split(' ');
        return clsArray.length > 1;
    });
    div.css('background','yellow');
});

Live example: http://jsfiddle.net/udBZy/3/

maxedison
  • 17,243
  • 14
  • 67
  • 114
0

It works just like regular CSS

$('.class1.class2') // will select elements with both classes
JonH
  • 32,732
  • 12
  • 87
  • 145
bfavaretto
  • 71,580
  • 16
  • 111
  • 150
  • 1
    That requires you to know the classes beforehand, and it only selects specific elements with multiple classes. – BoltClock Oct 04 '11 at 18:56