133

Say I have 4 div elements with class .navlink, which, when clicked, use .data() to set a key called 'selected', to a value of true:

$('.navlink')click(function() { $(this).data('selected', true); })

Every time a new .navlink is clicked, I would like to store the previously selected navlink for later manipulation. Is there a quick and easy way to select an element based on what was stored using .data()?

There don't seem to be any jQuery :filters that fit the bill, and I tried the following (within the same click event), but for some reason it doesn't work:

var $previous = $('.navlink').filter( 
    function() { $(this).data("selected") == true }
);

I know that there are other ways to accomplish this, but right now I'm mostly just curious if it can be done via .data().

Brian Tompsett - 汤莱恩
  • 5,753
  • 72
  • 57
  • 129
user113716
  • 318,772
  • 63
  • 451
  • 440

5 Answers5

209

your filter would work, but you need to return true on matching objects in the function passed to the filter for it to grab them.

var $previous = $('.navlink').filter(function() { 
  return $(this).data("selected") == true 
});
BaroqueBobcat
  • 10,090
  • 1
  • 31
  • 37
  • 6
    Please note that this is no longer the only way to do this, StefanoP has provided alternatives – Nathan Koop Feb 25 '13 at 20:25
  • 3
    @NathanKoop, not quite. See my comment on his answer. – Bryan Downing Feb 25 '13 at 22:26
  • For those who use a data attribute to find an otherwise unfindable element(id less divs etc... that you need to be able to access for whatever reason) at any location in the document: `$("*").filter(function() { return $(this).data("DATA IDENTIFIER HERE") == DATA VALUE HERE; });` – Tschallacka Jun 20 '13 at 13:37
  • this is not "messy" - this is the only safe way of filtering on arbitrary terms without requiring that you "escape" those values to ensure that the concatenation of the search term with the rest of the selector doesn't create an illegal selector. – Alnitak Dec 24 '18 at 11:25
164

Just for the record, you can filter on data with jquery (this question is quite old, and jQuery evolved since then, so it's right to write this solution as well):

$('.navlink[data-selected="true"]');

or, better (for performance):

$('.navlink').filter('[data-selected="true"]');

or, if you want to get all the elements with data-selected set:

$('[data-selected]')

Note that this method will only work with data that was set via html-attributes. If you set or change data with the .data() call, this method will no longer work.

Chronial
  • 66,706
  • 14
  • 93
  • 99
StefanoP
  • 3,798
  • 2
  • 19
  • 26
  • 9
    if the low vote count for this answer scares you - it is the accepted answer with 100+ votes for a virtually identical question http://stackoverflow.com/questions/4146502 – Simon_Weaver Dec 27 '12 at 02:57
  • 50
    -1 This doesn't work when data is set with the `.data()` method instead of a `data-` attribute. See this fiddle: http://jsfiddle.net/bryandowning/tySWC/ - Also, the `.find()` method searches for children of the preceding selector. In the example given, `data-selected` is an attribute of `.navlink`, not a child of `.navlink`. Also, `$('div p')` and `$('div').find('p')` are essentially equivalent. Using `.find()` seems like it may be slower due to the extra function call (although I'm not positive about this). Please correct me if I'm wrong about any of this (I really wish this method worked). – Bryan Downing Feb 25 '13 at 22:24
  • 3
    a couple of things: 1) you're right that this doesn't work if you set data with `.data()`, since jQuery searches through the DOM, I posted it for those (like me) who got to this question for other reasons; 2) correct, `.find()` searches through the children, so it's wrong in this example; 3) you're wrong, they are not equivalent, as jQuery searches right-to-left, see http://jonraasch.com/blog/10-advanced-jquery-performance-tuning-tips-from-paul-irish – StefanoP Feb 28 '13 at 08:30
  • 2
    Up vote for `$('[data-selected]')` it helped me out for something like `$('ul.categories a[data-categories_id]').click(......);` – Luke Cousins Jan 21 '15 at 17:19
  • Also, it seems like if you update the data attribute using .attr, if you retrieve it using .data the value will not be updated - so be careful when mixing the two – Fabio Lolli Jun 28 '17 at 12:22
13

We can make a plugin pretty easily:

$.fn.filterData = function(key, value) {
    return this.filter(function() {
        return $(this).data(key) == value;
    });
};

Usage (checking a radio button):

$('input[name=location_id]').filterData('my-data','data-val').prop('checked',true);
mpen
  • 272,448
  • 266
  • 850
  • 1,236
8

Two things I noticed (they may be mistakes from when you wrote it down though).

  1. You missed a dot in the first example ( $('.navlink').click )
  2. For filter to work, you have to return a value ( return $(this).data("selected")==true )
Bryan Downing
  • 15,194
  • 3
  • 39
  • 60
Thomas
  • 4,889
  • 4
  • 24
  • 19
-2

Sounds like more work than its worth.

1) Why not just have a single JavaScript variable that stores a reference to the currently selected element\jQuery object.

2) Why not add a class to the currently selected element. Then you could query the DOM for the ".active" class or something.

Bryan Migliorisi
  • 8,982
  • 4
  • 34
  • 47