Matthias
Matthias

Reputation: 12259

Select elements with empty or not-specified attribute

Take the following, schematic html-code:

<div>
  <span id='1' cust-attr='' />
  <span id='2' />
  <span id='3' cust-attr='Foo' />
</div>

Now I am looking for a selector finding all spans which either do not have an attribute "cust-attr" or whose "cust-attr" value is empty.
In this case, this would be the 1 and 2.

I tried the following selectors with the following results:

  1. span[cust-attr!=] selects 2 and 3
  2. span[cust-attr=''] only selects 1
  3. span:not([cust-attr]) selects 2
  4. span(:not([cust-attr]),[cust-attr='']) selects all three
  5. span([cust-attr=''],:not([cust-attr])) selects 1

However, I did not find one selecting only 1 and 2.
Do you know a possibility?

Note that I want to avoid:

span:not([cust-attr]),span[cust-attr='']

as "span" is in reality a more complex expression.

Upvotes: 10

Views: 13385

Answers (4)

aryomuzakki
aryomuzakki

Reputation: 106

For modern browser, you can use :where() or :is()

(widely available since 2021)

Like this:

span:where([cust-attr=""], :not([cust-attr]))

or this:

span:is([cust-attr=""], :not([cust-attr]))

The only difference of :where() vs :is() are the specificity

From MDN

The difference between :where() and :is() is that :where() always has 0 specificity, whereas :is() takes on the specificity of the most specific selector in its arguments.

Using :where() will not increase the specificity. Using :is() will use the highest selector specificity.

specificity: id > class | attribute | pseudo-class > element.

Note: pesudo-element selector will not work in both (ie: ::before).

Demo

span:where([cust-attr=""], :not([cust-attr])) {
  text-decoration: underline;
}

span:is([cust-attr=""], :not([cust-attr])) {
  color: red;
}
<div>
  <span id='1' cust-attr="">Text 1</span>
  <span id='2'>Text 2</span>
  <span id='3' cust-attr='Foo'>Text 3</span>
</div>

Upvotes: 0

JeffC
JeffC

Reputation: 25587

Late to the party...

... or you could use CSS Selectors and be 10x as fast as both jQuery answers... :)

document.querySelectorAll("input:not([id]), input[id='']");

Proof

Upvotes: 15

lonesomeday
lonesomeday

Reputation: 237845

Basically, don't.

It's not good practice to put all your logic into the selector. It will end up being computationally highly expensive (because the parts need to be parsed out of a string before they are interpreted) and messy. Use the beauty of the filter method instead:

$('span')
    .filter(function(){
        return !$(this).attr('cust-attr');
    });

This removes all elements where cust-attr is a non-empty string from the selection.

Upvotes: 6

James
James

Reputation: 111900

Why not just select all the SPANs first and then filter the selection down? E.g.

$('span').filter('[cust-attr=""],:not([cust-attr])')

Upvotes: 4

Related Questions