13

I'm trying to use data- attributes in an HTML table to store data about an item that will later be used in an ajax call, but I'm having trouble with my jQuery selection when I try to get the data back out.

This works:

var listItemId = $(this).parent().parent().attr('data-id');

However, the .parent().parent() selector is too fragile--it'll break if I ever change my HTML structure.

This is what I'd like to do, but it is returning undefined:

var listItemId = $(this).parent('.list-item').attr('data-id');

My HTML looks like this:

<tr class="list-item" data-id="1">
   <td>
     <input value="Some text entered by the user" type="text" >
   </td>
</tr>

What am I missing?

Josh Earl
  • 18,151
  • 15
  • 62
  • 91

4 Answers4

27

internally, jquery uses .closest for this kind of stuff.

var listItemId = $(this).closest('tr').attr('data-id');

moreover if you have nested tables (which I never saw, but we never know), you have to select the first 'tr' too. (it's more useful with looking for divs than rows though). However, for code unification, I never use parents when I need closest. That way, the function names implies it's meaning exactly (closest parent), while .parents() leaves more room to interpretation, and thus reduce code readability (imo)

performance wise, they are equivalent (check this jsperf )

finally, you can consider a pure javasrcipt approache too: parentNode (by miles faster than anything else, if you really need speed)

in your case:

var listItemId = $(this.parentNode.parentNode).attr('data-id');

or

var listItemId = this.parentNode.parentNode.attributes['data-id'].value;

NB: pure javascript methods need valid html to work, unlike the one in your question (close your input tag, and add a table one).

here is a little fiddle

roselan
  • 3,755
  • 1
  • 20
  • 20
  • Thanks for the detailed answer. I'm considering your point about expressing intent. Might opt for that route... – Josh Earl Nov 11 '11 at 13:53
  • I would use .data('id') instead of .attr('data-id'); – RubbelDeCatc Jul 18 '16 at 11:24
  • Me too, or parentNode.dataset.id. My best guess is that .data() was buggy in 2011... yup: http://stackoverflow.com/questions/5309926/how-to-get-the-data-id-attribute – roselan Jul 18 '16 at 13:22
4

try

var listItemId = $(this).parents('.list-item').attr('data-id');

parents() goes up in the tree until it matches the selector

Manuel van Rijn
  • 10,170
  • 1
  • 29
  • 52
3

I would suggest:

var listItemId = $(this).parents('tr').data('id');

The class selector is the slowest of all the jQuery selectors and should avoided unless there is no other way to go the information you need.

UPDATE

I fixed the syntax to make use of the .data() method correctly. This way only works in version 1.4.3 or higher.

arb
  • 7,753
  • 7
  • 31
  • 66
  • This answer mostly worked. If I do `$(this).parents('tr').attr('data-id');` it works perfectly. Any idea why the `.data.id` form wouldn't be working? – Josh Earl Nov 11 '11 at 13:52
  • 1
    Opps. My syntax was wrong. Try `.data('id')` instead. This is assuming you are using jQuery 1.4.3 or higher. – arb Nov 11 '11 at 15:24
0
$(this).closest('tr').attr('data-id');

This will be the best solution for your problem. The code will not be depended on you html structure, unless you introduce new <tr> tag in between