Yanick Rochon
Yanick Rochon

Reputation: 53536

jQuery UI :data selector does not return HTML5 data attributes

Let say I have this piece of HTML :

<div id="container">
   <ul>
       <li><a href="#" data-some-info="foo">Bar</a>
       <!-- repeating a few like the one -->                          -->
       <!-- above for a while ...        -->
   </uL>
</div>

And I want to apply something to all the anchor elements with the data some-info when it is defined.

I just want to understand why this behaviour (is it a bug?)

$("#container").find("a:data(some-info)").size();  // -> 0
$("#container").find("a").data("some-info");       // -> "foo"
$("#container").find("a:data(some-info)").size();  // -> 1 (actual expected val)

Any ideas?

More Info : I'm using jQuery 1.9.0, and jQuery UI 1.9.2

** Edit **

I know about $("#container").find("a[data-some-info]"). This is not what I question here. If there is a data selector, why does it behave this way?

Upvotes: 5

Views: 916

Answers (3)

Selvakumar Arumugam
Selvakumar Arumugam

Reputation: 79830

From Docs,

The expression $( "div:data(foo)") matches a <div> if it has data stored via .data( "foo", value )

And from jquery code ->

jQuery data() is stored in a separate object inside the object's internal data cache in order to avoid key collisions between internal data and user-defined data (comment from jQuery code)

https://github.com/jquery/jquery/blob/master/src/data.js#L51

https://github.com/jquery/jquery/blob/master/src/data.js#L63

When it is defined in the HTML, it is just a user defined data element which will NOT be selected by the jQuery :data selector.

However when you call .data(some-info), it actually reads the user defined data and copies it to the internal data and later using :data picks up the element as it could find it in the internal data.

It is NOT a bug, as this is clearly mentioned in the docs.


You should use .length which is a property to get the number of returned elements from the selector.

Also .size is deprecated since as of jQuery 1.8. http://api.jquery.com/size/

Upvotes: 1

Kevin B
Kevin B

Reputation: 95018

This is how the selector is implemented:

$.extend( $.expr[ ":" ], {
    data: $.expr.createPseudo ?
        $.expr.createPseudo(function( dataName ) {
            return function( elem ) {
                return !!$.data( elem, dataName );
            };
        }) :
        // support: jQuery <1.8
        function( elem, i, match ) {
            return !!$.data( elem, match[ 3 ] );
        },

(Ref. https://github.com/jquery/jquery-ui/blob/master/ui/jquery.ui.core.js#L160)

Note how it is using $.data rather than $(elem).data. This means it is only looking for data that has been stored on the element through either the $.data or $().data method. It does not look for data attributes on the element and i do not think it is intended for that purpose. The attribute equals selector is what you should be using. [data-foo] Note however that it looks at the attribute, if you add data to an element with jQuery's $().data it may not match that selector if jQuery doesn't update the attribute.

Upvotes: 3

Plynx
Plynx

Reputation: 11461

The :data selector is not part of JQuery core. It might be a bug, but the JQuery docs say that HTML5 data attributes are pulled into the internal JQuery data object (presumably on calls to .data) rather than being available as part of a :data pseudo-selector (which according to the JQuery UI docs queries the internal data representation as is and says nothing about HTML5 data attributes)

Alternate approach:

Use $("#container").find("a[data-some-info='foo']"), or for if anything is set on the data attribute, .find("a[data-some-info]").

Upvotes: 1

Related Questions