views:

334

answers:

3

Hi,

how do I select special attributes like 'user:name' or 'city:id' using jQuery?

<div user:name="Ropstah"></div>
<span city:id="4"></div>

Javascript

//this works:
alert($('div').attr("user:name"));  // alerts 'Ropstah'

//this doesn't work:
alert($('div[user:name]').attr("user:name"));    //error
alert($('div[user\\:name]').attr("user:name"));    //error even with special character escaping...
+2  A: 

If you're OK with using non-standard properties (which doesn't effect the rendering of your markup in any way.. it's pretty harmless, really) you can do this:

<div nonstandard="harmless" />

$("div[nonstandard='harmless']")

I've used this approach a few times. It doesn't hurt to be pragmatic.

roosteronacid
Ah. You tested that yourself :) Then it's back to my first suggestion: change your markup.
roosteronacid
What is W3C standard for custom attributes? And how can I select those using jQuery? I can change markup easily...
Ropstah
Not if he's using XHTML served as application/xhtml+xml, in which case it's perfectly acceptable to define additional XML namespaces within which elements and attributes can live.
NickFitz
roosteronacid
@NickFitz: You're right. But even with the right DTD my guess is that jQuery will still fail.
roosteronacid
Yes that's what I kept on doing, but I want to make it more 'safe' so that it won't interfere with possible other javascript...
Ropstah
You could implement a naming convention. But I doubt that your custom properties will be overridden. They are after all.. custom :)
roosteronacid
I think my plugin is a little neater :p No need to create an array for this...
Paolo Bergantino
@Paolo Bergantino: You are right. Yours is a bit more slick.
roosteronacid
+4  A: 

This is a bug in jQuery.

You have two options:

  • Get rid of the : and using "non standard" attributes (honestly, it's not a big deal)
  • Get more verbose, or use a plugin to get the functionality anyways:

Initially, you might have to do this:

$('div').filter(function() {
    return $(this).attr('user:name') !== undefined;
}).whateverElse();

Speed wise this should be fairly close to jQuery's [] selector as that's what it's doing inside the library anyways. It is, of course, more to type every time you want to find an element that has an attribute, so you could write a plugin for it, since jQuery is awesome and lets you do this sort of thing:

$.fn.hasattr = function(attr) {
    return this.filter(function() {
        return $(this).attr(attr) !== undefined;
    });
};

Which would then let you do a much simpler:

$('div').hasattr('user:name').whateverElse();

Or if you wanted to check if the attribute was equal to something, the plugin might be:

$.fn.cmpattr = function(attr, value) {
    return this.filter(function() {
        return $(this).attr(attr) == value;
    });
};

And you could then do:

$('div').cmpattr('user:name', 'Ropstah').whateverElse();
Paolo Bergantino
I agree. The "non-standard" attribute thing sometimes is the way to go . Some people might disagree with breaking the standards.. but that's usually people who think that being a programmer is to stick to the spec rather than solve a problem :)
roosteronacid
I'm a problem solver :)
Ropstah
+3  A: 

Fix it:

jQuery.expr.match.ATTR = /\[\s*((?:[\w\u00c0-\uFFFF_-]|\\.)+|\w+:\w+)\s*(?:(\S?=)\s*(['"]*)(.*?)\3|)\s*\]/;
//                                                          ^^^^^^^^


EDIT: This is not an official fix, it appears to work quite well though.

I've had quite a few headaches caused by jQuery and its inner-workings... sometimes, I think, it's okay to get stuck in there and fix it yourself. :)

J-P
Nice. At first I wasn't sure if it was such a hot idea to edit the regex directly, but heck, why not.
Paolo Bergantino
Is this an official fix? Has this been through the test-suite?
roosteronacid
Pretty sure he just whipped this up.
Paolo Bergantino
http://www.codinghorror.com/blog/archives/001268.html :)
roosteronacid
@roosteronacid, StackOverflow IS a bathroom-wall of code...
J-P
@J-P: Hehe, I see your point ;)
roosteronacid