2

So I'm trying to select elements with multiple classes only if the classes are all found in a set of classes.

Example. I have a element with id="foo" and class="red blue"

I then have some given set of colors. From which I want to select all elements that I have within the set.

Lets say i have the set {red} nothing should be found. {red blue} then 'foo' should be found. And then if I have {red blue green} then 'foo' should still be found.

I've tried this with the multiple selectors but it does not work once the set is larger than just {red blue}

$.('.red') will return foo (which is not what I want.)
$.('.red.blue') will return foo (good!)
$.('.red.blue.green') will return nothing (bad.)

I'm not sure the 'or' operator here is what I want either. $.('.red,.blue') will then return any elements with red OR blue, which is not what I want. I've already got that function figured out.

is there any sort of 'all in' function?

I was thinking about just iterating every selection query possible with the set of items, but that becomes a lot of queries very quickly when the set is > 4 items long.

6
  • 1
    Couldn't understand what's wrong with .red.blue.green?
    – Itay
    Commented Sep 12, 2013 at 6:40
  • Can you make a fiddle (jsfiddle.net) to show us what is the current result and what you expect.
    – JofryHS
    Commented Sep 12, 2013 at 6:45
  • 1
    didn't understand what you want to accomplish ??
    – FosterZ
    Commented Sep 12, 2013 at 6:46
  • He wants to select an element with the class red and blue, by giving the selectors, red, blue and green.
    – Razz
    Commented Sep 12, 2013 at 6:57
  • @Razz This makes no sense at all.
    – Itay
    Commented Sep 12, 2013 at 6:58

6 Answers 6

1

Note: It is a conceptual solution... you will have to adapt it to your specific requirement

function x($targets, array){
    var filtered = $targets.filter(function(){
        var classNames = this.className.split(/\s+/), valid = true;
        $.each(classNames, function(idx, value){
            if($.inArray(value, array) == -1){
                valid = false;
                return false;
            }
        });
        return valid;
    });
    //do something
    return filtered;
}

then

//this is the set of elements against which the tests have to be done
var $targets = $('#ct').children();

x($targets, ['red']);
x($targets, ['red', 'green']);

Demo: Fiddle

0

I don't know exactly what is the context of your question, but if it's, for example, color related, I guess there is a finite number of class.

The way I would go about that would be the opposite. Instead of selecting the colors you have, filter away those that don't match your expected result.

For example let's say you have for color class .blue, .red, .green, .yellow. To match the filters you used in your example, that would be

:not(.blue,.green,.yellow) /*foo does not match, it is blue*/
:not(.green,.yellow) /*Match*/
:not(.yellow) /*Match*/

You still have to figure how to construct the set. But that's another question.

0

Edit:
I got it reverse the first time, here is a better example code:

var requiredClasses = ['red', 'blue'];  
var relevant = $('#my_div span');

var result = [];
elements_loop:
for(i = 0; i< relevant.lenght; ++){
   var el = relevant[i];
   var classList = el.attr('class').split(/\s+/);
   $.each( classList, function(i, cls){
       if (! $.inArray(cls, requiredClasses) {
          //skip the element if any of its class is not in the set.
          break elements_loop;        
       }
   });
   result.push(el);
}
return result;

The code can be optimized, just giving you the idea.

0

You can try below function. It takes an array of classes:

function GetElements(classes) {
    var selector = "";
    for (var i = 0; i < classes.length; i++) {
        if (selector != "") selector += ",";
        selector += "." + classes[i];
    }

    return $(selector).filter(

    function () {
        var ele = $(this);
        var eleClasses = ele.attr('class').split(' ');

        if (classes.length < eleClasses.length) {
            return false;
        }

        var matched = 0;
        for (var i = 0; i < eleClasses.length; i++) {
            for (var j = 0; j < classes.length; j++) {
                if (eleClasses[i] == classes[j]) {
                    matched++;
                    break;
                }
            }
        }

        return eleClasses.length === matched;
    });
}

Try it @ http://jsfiddle.net/purnil/maWhP/3/

0

you can try this: http://jsfiddle.net/maWhP/7/

$(function () {
    var selector = ['.red','.blue','.green','.other'];
    $r = $(selector.join(', ')); // select all 
    $r.each(function() {
        var $t = $(this);
        $.each(selector, function (i, sel) { // each selector
            if ( !$t.hasClass(sel.substring(1)) ) { // remove if selector not match
               $r = $r.not($t);     
               return false; // break the loop                
            }
        });     
    });
    $r; // is what you want
});
0

I figured out a fairly straight forward way. I have a divs with the classes of colors.

I just make an array of all of the different elements classes (arrays). Then I test them against the input colors.

var user_colors = ['red', 'white', 'blue'];
var all_colors = [['red', 'green', 'blue', 'white'], ['red', 'blue'], ['red', 'white']];  //this array is constructed from the elements I'm interested in

$(all_colors).each(function(i, rec) {
if($(rec).not(user_colors).length == 0) {
  str = "";
  str = "." + rec.join('.');
  $(str).fadeIn("slow");
}
});

this will fade in something with the class red and white eg. div class="red white"

However I'm having a slight problem with the $(.foo.bar.ed) selector. Sometimes it seems at random it will also select elements with additional classes. eg. $(.foo.bar.ed) will get something with class="foo bar ed dog cat". Any ideas?

Thanks for all the input! D.rave and Arun P Johny helped nail it.

Not the answer you're looking for? Browse other questions tagged or ask your own question.