109

Select elements that i have previously set with jquery.data();

i.e. Select all elements with .data('myAttr') already been set.

SOLUTION

A jsfiddle to demostrate is Fiddle

Ashkan Mobayen Khiabani
  • 33,575
  • 33
  • 102
  • 171
Argiropoulos Stavros
  • 9,436
  • 11
  • 61
  • 79

7 Answers7

115

You could do

$('[data-myAttr!=""]'); 

this selects all elements which have an attribute data-myAttr which is not equal to '' (so it must have been set); (only for elements that have their data attribute set in HTML not via jQuery)

you could also use filter() (which works for data attributes set from jQuery)

$('*').filter(function() {
    return $(this).data('myAttr') !== undefined;
});
Matthew Lock
  • 13,144
  • 12
  • 92
  • 130
Nicola Peluchetti
  • 76,206
  • 31
  • 145
  • 192
80

The best and simple way to select them is:

$('[data-myAttr]')

More Information:

I tested a lot of things.

Using $('[data-myAttr!=""]') doesn't work for all cases. Because elements that do not have a data-myAttr set, will have their data-myAttr equal to undefined and $('[data-myAttr!=""]') will select those as well, which is incorrect.

Ashkan Mobayen Khiabani
  • 33,575
  • 33
  • 102
  • 171
  • 6
    This only works with data attributes defined in the markup. It does NOT work with data attributes defined via jQuery, see https://jsfiddle.net/2p7h0Lj8/1/ – Sophivorus Jun 25 '16 at 23:13
22

You can use filter():

var elements = $("*").filter(function() {
    return $(this).data("myAttr") !== undefined;
});
Frédéric Hamidi
  • 258,201
  • 41
  • 486
  • 479
  • 1
    Was about to post this, here's a fiddle to show it works: http://jsfiddle.net/gbHFZ/1/ – Rory McCrossan Feb 29 '12 at 13:34
  • 1
    Why attribute selector doesn't do the job? `$('[data-myAttr]')` ? – gdoron Feb 29 '12 at 13:36
  • 8
    @gdoron, that's because `data()`'s getter form does indeed read the HTML5 `data-` attributes, but its setter form neither creates nor updates them. – Frédéric Hamidi Feb 29 '12 at 13:37
  • ummm, so where does it save the data? can you give my a reference? I read this _"(all data values are then stored internally in jQuery)."_ but where??? – gdoron Feb 29 '12 at 13:38
  • I have been thinking about the "undefined" check.. I have read that proper way would be 'typeof n !== "undefined"'. Is that check what you're using actually the same but shorter? – Tx3 Feb 29 '12 at 13:40
  • 3
    @gdoron, the data is persisted in a global cache, keyed by an id which is associated with the element through an expando property. – Frédéric Hamidi Feb 29 '12 at 13:40
  • So how can I reach that data without `.data()`? – gdoron Feb 29 '12 at 13:42
  • @Tx3, the `typeof x !== "undefined"` pattern is useful to check undeclared variables (see http://stackoverflow.com/questions/2703102/typeof-undefined-vs-null). This is overkill here, since we're not working with a variable that might be undeclared. – Frédéric Hamidi Feb 29 '12 at 13:43
  • @gdoron, you cannot do that without reproducing part of jQuery's internal implementation details. But why would you want to access information registered by the setter form of `data()` without using its getter form? – Frédéric Hamidi Feb 29 '12 at 13:44
  • It was great, helped me a lot. Thanks for best answer. – BaiMaoli Sep 29 '20 at 23:04
19

You could use this jQuery Selector extention: Querying element data

$(':data');       // All elements with data  
$(':not(:data)'); // All elements without data
roberkules
  • 6,557
  • 2
  • 44
  • 52
  • 1
    jQuery UI has this already so some may not need to call the anonymous function. http://api.jqueryui.com/data-selector/ – arleslie Oct 12 '14 at 01:07
9

You can use JQuery UI with the :data() selector

Selects elements which have data stored under the specified key.

Check this jsfiddle for an example

To get all elements matching .data('myAttr') you can use

var matches = $(':data(myAttr)');

This should work for both elements with data- attributes and elements with data stored using $.data() because

As of jQuery 1.4.3 HTML 5 data- attributes will be automatically pulled in to jQuery's data object.

But this doesn't work very well. Check this jsfiddle and you will see that the second time the selector is called it should match 2 elements and is only matching one. This is due to "a bug" in the jquery-ui library.

This is taken from the core jquery-ui file.

 $.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 ] );
        }
});

As you can see they are using $.data(elem, match) instead $(elem).data(match) which causes the cache not to be updated in case you are requesting elements with data- attributes. If the element has been tested for data() storage this works well but if not it will not be included in the resulting matches.

This might not be a bug at all if what you want is to match only elements with data information set by you but if not you are left with two options.

  1. Don't use jquery-ui and extend your own pseudo-selector $(:mydata(myAttr))

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

     // pseudoselector code
     $.extend($.expr[":"], {
       mydata: $.expr.createPseudo ?
         $.expr.createPseudo(function(dataName) {
           return function(elem) {
             return !!$(elem).data(dataName);
           };
         }) : function(elem, i, match) {
           return !!$(elem).data(match[3]);
         }
     });
     // end pseudoselector
    
     testSelector = function() {
       var matched = $(':mydata(test)'),
         results = $('#results');
       results.append('<div>You matched ' + matched.length + ' elements</div>');
       matched.css('border', 'black 3px solid');
       console.log(matched);
       console.log('You matched ' + matched.length + ' elements');
     };
    
     testSelector();
     $('#addData').click(function() {
       $(".bar").data('test', 'value2');
       testSelector();
     });
    
     
     .foo {
       background-color: red;
       color: white;
     }
     .bar {
       background-color: blue;
       color: white;
     }
     #addData {
       margin-top: 20px;
     }
    
     
     <script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js"></script>
     <div>
       <span class="bar">without data attribute</span>
       <span class="foo" data-test="value1">with data attribute</span>
     </div>
     <button id="addData" type="button">Add data</button>
     <div id="results"></div>
    
     
  2. Use jquery-ui with the :data pseudoselector and join the results of selecting [data-myAttr] to include the ones that might be skipped

    var matches = $(':data(myAttr)', '[data-myAttr]')
    

     testSelector = function() {
       var matched = $(':data(test), [data-test]'),
           results = $('#results');
       results.append('<div>You matched ' + matched.length + ' elements</div>');
       matched.css('border', 'black 3px solid');
       console.log(matched);
       console.log('You matched ' + matched.length + ' elements');
     };
    
     testSelector();
     $('#addData').click(function() {
       $(".bar").data('test', 'value2');
       testSelector();
     });
    
     
     .foo {
       background-color: red;
       color: white;
     }
     .bar {
       background-color: blue;
       color: white;
     }
     #addData {
       margin-top: 20px;
     }
    
     
     <script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js"></script>
     <script src="http://code.jquery.com/ui/1.11.4/jquery-ui.js"></script>
     <div>
       <span class="bar">without data attribute</span>
       <span class="foo" data-test="value1">with data attribute</span>
     </div>
     <button id="addData" type="button">Add data</button>
     <div id="results"></div>
    
     
devconcept
  • 3,665
  • 1
  • 26
  • 40
  • This was part of the solution to my problem of selecting elements with data-* attributes without knowing the actual id or data attribute name. I found the way to extend jQuery to do this, elsewhere, but +1 here for the code snippet to show practical application. Others give just enough to hint, but sometimes you need to SHOW how to USE the information provided. Thanks! :) – Brandon Elliott Jun 01 '16 at 04:59
8
$('[data-myAttr]').each(function() {
       var element = $(this);
       // Do something with the element
});
Andy B
  • 101
  • 1
  • 8
Khalid
  • 111
  • 1
  • 3
2

Select elements that i have previously set with jquery.data();


The question is for finding all elements with a specific key and not any data.


Try utilizing jQuery.data()

$(".myClass").each(function(i){
    if( i % 2 == 0 ){
        $(this).data("myAttr",i + 1);                
    }
});
    
var res = $(".myClass").map(function(i) {
    console.log($(this).data("myAttr"));
    return $.data(this, "myAttr") !== undefined ? this : null
});    

console.log(res);
<script src="https://ajax.googleapis.com/ajax/libs/jquery/1.11.1/jquery.min.js">
</script>
<div class="myClass">1</div>
<div class="myClass">2</div>
<div class="myClass">3</div>
<div class="myClass">4</div>
<div class="myClass">5</div>

jsfiddle http://jsfiddle.net/xynZA/142/

guest271314
  • 1
  • 15
  • 104
  • 177