tags:

views:

85

answers:

4

If I have the following:

<div class="apple-monkey"></div>
<div class="apple-horse"></div>
<div class="cow-apple-brick"></div>

I can use the following selector to find the first two DIVs:

$("div[class^='apple-']")

However, if I have this:

<div class="some-other-class apple-monkey"></div>
<div class="apple-horse"></div>
<div class="cow-apple-brick"></div>

It will only find the second DIV, since the first div's class is returned as a string (I think) and doesn't actually start with 'apple-' but rather 'some-'

One way around that is to not use starts with, but instead contains:

$("div[class*='apple-']")

The problem with that is it will also select the 3rd DIV in my example.

Question: Via jQuery, what is the proper way to use predicate selectors on individual class names, rather than the entire class attribute as a string? Is it just a matter of grabbing the CLASS, then splitting it into an array and then looping through each individual one with regex? Or is there a more elegant/less verbose solution?

+1  A: 

I'd recommend making "apple" it's own class. You should avoid the starts-with/ends-with if you can because being able to select using div.apple would be a lot faster. That's the more elegant solution. Don't be afraid to split things out into separate classes if it makes the task simpler/faster.

Parrots
How do you figure it would be alot faster? It still has to scan the entire DOM and evaluate the class attribute. It would be marginally faster (at best) because it would not have to substring the class attribute. Negligible.
Josh Stodola
http://www.componenthouse.com/article-19 : If you look in the get by class section, using the regular dot syntax is usually a decent bit faster than treating the class as an attribute. Add the substring searching (and the additional work he'll have to do to break out elements with multiple class names) and it'll add up to a decent performance savings.
Parrots
I agree. The catch is that we're still heavily supporting IE6 and it doesn't support compound selectors in CSS: .class1.class2.class3 as such, we're relying on using longer class names where 'parameters' are divided by dashes.
DA
@Parrots thanks for the link to that article. We'll have to do some thinking about this.
DA
A: 

How about the jQuery regex selector plugin http://james.padolsey.com/javascript/regex-selector-for-jquery/

Dave.Sol
+1  A: 

Try this:

$("div[class]").filter(function() {
    var classNames = this.className.split(/\s+/);
    for (var i=0; i<classNames.length; ++i) {
        if (classNames[i].substr(0, 6) === "apple-") {
            return true;
        }
    }
    return false;
})
Gumbo
thanks for that. That was my inclination as well--that I'd just have to split it up myself.
DA
+2  A: 

Classes that start with "apple-" plus classes that contain " apple-"

$("div[class^='apple-'],div[class*=' apple-']")
Josh Stodola
+1. Although I agree with @parrots' suggestion that "apple" should be its own class here, since it obviously overlaps multiple divs yet is a distinct entity. But this does solve the problem.
jvenema
Hmm...clever! I hadn't thought of using space in there. Can one use boolean operators in a jquery selector? Ideally, the above would be 'OR' to avoid the (rare and likely avoidable) case where there are more than one class staring with 'apple-'
DA
Not sure I understand, but if you only want to use the second selector when the first selector returns zero elements, you could do something like this: `var divs = $("div[class^='apple-']"); if(divs.length == 0) divs = $("div[class*=' apple-']");`
Josh Stodola
@Josh now that I think about it, your initial solution works just fine. A DIV that had a class like "apple-brick apple-horse" would still be just selected once into the jQuery object.
DA