1151

I've got the following scenario:

var el = 'li';

and there are 5 <li>'s on the page each with a data-slide=number attribute (number being 1,2,3,4,5 respectively).

I now need to find the currently active slide number which is mapped to var current = $('ul').data(current); and is updated on each slide change.

So far my tries have been unsuccessful, trying to construct the selector that would match the current slide:

$('ul').find(el+[data-slide=+current+]);

does not match/return anything…

The reason I can't hardcode the li part is that this is a user accessible variable that can be changed to a different element if required, so it may not always be an li.

Any ideas on what I'm missing?

Frédéric Hamidi
  • 258,201
  • 41
  • 486
  • 479
Jannis
  • 17,025
  • 18
  • 62
  • 75
  • 6
    you sure within your `.find(el+[data-slide=+current+]);` is the code that you write? it seems you missed some quotations to `"[data-slide]"` – xandy Nov 16 '10 at 05:20
  • That's what helped me to select **all** data attributes (regardless the value): `$('*[data-slide]')` You can use it with e.g. `$('*[data-slide]').each( function() { ... });` – Avatar Jan 14 '20 at 08:17

9 Answers9

1721

You have to inject the value of current into an Attribute Equals selector:

$("ul").find(`[data-slide='${current}']`)

For older JavaScript environments (ES5 and earlier):

$("ul").find("[data-slide='" + current + "']"); 
Frédéric Hamidi
  • 258,201
  • 41
  • 486
  • 479
  • 86
    I worry that this won't work if data was added via jQuery .data(...) function, since this doesn't always render an attribute and soemtimes uses browser specific storage mechanism. Another reason that I wish jQuery core had a data specific selector. – AaronLS Oct 31 '12 at 18:43
  • 88
    Notice that it doesn't work for elements where you set data with $('#element').data('some-att-name', value); but only for those with hardcoded attribute. I've got this problem and to make it work set data by writing the attribute directly $('#element').attr('data-some-att-name', value); – Pawel Oct 28 '13 at 16:55
  • 1
    Geepers, I lost a couple of hours here! Confirming that adding the data-{somevalue} with attr dynamically allows you to use Jquery selector to find data field. – Vinnie Amir Sep 06 '22 at 06:00
556

in case you don't want to type all that, here's a shorter way to query by data attribute:

$("ul[data-slide='" + current +"']");

FYI: http://james.padolsey.com/javascript/a-better-data-selector-for-jquery/

John
  • 29,788
  • 18
  • 89
  • 130
KevinDeus
  • 11,988
  • 20
  • 65
  • 97
  • 36
    For those of you who care, given the structure `
    ` this answer's selector will return undefined so it does not work given the user's scenario. This answer WILL work for the structure `
    ` While I understand why its popularity due to brevity, it is technically an incorrect answer. http://jsfiddle.net/py5p2abL/1/
    – akousmata Dec 04 '14 at 15:15
  • Just put a space between the ul and the brackets and it will work. – Artem Jan 05 '22 at 06:29
251

When searching with [data-x=...], watch out, it doesn't work with jQuery.data(..) setter:

$('<b data-x="1">'  ).is('[data-x=1]') // this works
> true

$('<b>').data('x', 1).is('[data-x=1]') // this doesn't
> false

$('<b>').attr('data-x', 1).is('[data-x=1]') // this is the workaround
> true

You can use this instead:

$.fn.filterByData = function(prop, val) {
    return this.filter(
        function() { return $(this).data(prop)==val; }
    );
}

$('<b>').data('x', 1).filterByData('x', 1).length
> 1
psycho brm
  • 7,494
  • 1
  • 43
  • 42
74

Without JQuery, ES6

document.querySelectorAll(`[data-slide='${CSS.escape(current)}']`);

I know the question is about JQuery, but readers may want a pure JS method.

Dmitriy Sintsov
  • 3,821
  • 32
  • 20
rap-2-h
  • 30,204
  • 37
  • 167
  • 263
43

I improved upon psycho brm's filterByData extension to jQuery.

Where the former extension searched on a key-value pair, with this extension you can additionally search for the presence of a data attribute, irrespective of its value.

(function ($) {

    $.fn.filterByData = function (prop, val) {
        var $self = this;
        if (typeof val === 'undefined') {
            return $self.filter(
                function () { return typeof $(this).data(prop) !== 'undefined'; }
            );
        }
        return $self.filter(
            function () { return $(this).data(prop) == val; }
        );
    };

})(window.jQuery);

Usage:

$('<b>').data('x', 1).filterByData('x', 1).length    // output: 1
$('<b>').data('x', 1).filterByData('x').length       // output: 1

// test data
function extractData() {
  log('data-prop=val ...... ' + $('div').filterByData('prop', 'val').length);
  log('data-prop .......... ' + $('div').filterByData('prop').length);
  log('data-random ........ ' + $('div').filterByData('random').length);
  log('data-test .......... ' + $('div').filterByData('test').length);
  log('data-test=anyval ... ' + $('div').filterByData('test', 'anyval').length);
}

$(document).ready(function() {
  $('#b5').data('test', 'anyval');
});

// the actual extension
(function($) {

  $.fn.filterByData = function(prop, val) {
    var $self = this;
    if (typeof val === 'undefined') {
      return $self.filter(

        function() {
          return typeof $(this).data(prop) !== 'undefined';
        });
    }
    return $self.filter(

      function() {
        return $(this).data(prop) == val;
      });
  };

})(window.jQuery);


//just to quickly log
function log(txt) {
  if (window.console && console.log) {
    console.log(txt);
    //} else {
    //  alert('You need a console to check the results');
  }
  $("#result").append(txt + "<br />");
}
#bPratik {
  font-family: monospace;
}
<script src="https://ajax.googleapis.com/ajax/libs/jquery/1.11.1/jquery.min.js"></script>

<div id="bPratik">
  <h2>Setup</h2>
  <div id="b1" data-prop="val">Data added inline :: data-prop="val"</div>
  <div id="b2" data-prop="val">Data added inline :: data-prop="val"</div>
  <div id="b3" data-prop="diffval">Data added inline :: data-prop="diffval"</div>
  <div id="b4" data-test="val">Data added inline :: data-test="val"</div>
  <div id="b5">Data will be added via jQuery</div>
  <h2>Output</h2>
  <div id="result"></div>

  <hr />
  <button onclick="extractData()">Reveal</button>
</div>

Or the fiddle: http://jsfiddle.net/PTqmE/46/

Community
  • 1
  • 1
bPratik
  • 6,894
  • 4
  • 36
  • 67
40

I have faced the same issue while fetching elements using jQuery and data-* attribute.

so for your reference the shortest code is here:

This is my HTML Code:

<section data-js="carousel"></section>
<section></section>
<section></section>
<section data-js="carousel"></section>

This is my jQuery selector:

$('section[data-js="carousel"]');
// this will return array of the section elements which has data-js="carousel" attribute.
Matthew R.
  • 4,332
  • 1
  • 24
  • 39
user1378423
  • 567
  • 5
  • 3
25
$("ul").find("li[data-slide='" + CSS.escape(current) + "']");

I hope this may work better

thanks

Dmitriy Sintsov
  • 3,821
  • 32
  • 20
24

This selector $("ul [data-slide='" + current +"']"); will work for following structure:

<ul><li data-slide="item"></li></ul>  

While this $("ul[data-slide='" + current +"']"); will work for:

<ul data-slide="item"><li></li></ul>

Matas Vaitkevicius
  • 58,075
  • 31
  • 238
  • 265
15

Going back to his original question, about how to make this work without knowing the element type in advance, the following does this:

$(ContainerNode).find(el.nodeName + "[data-slide='" + current + "']");
Emil
  • 7,220
  • 17
  • 76
  • 135
Bryan Garaventa
  • 151
  • 1
  • 2