353

The following code returns 'undefined'...

$('select').change(function(){
    alert($(this).data('id'));
});

<select>
    <option data-id="1">one</option>
    <option data-id="2">two</option>
    <option data-id="3">three</option>
</select>
userBG
  • 6,860
  • 10
  • 31
  • 39

10 Answers10

825

You need to find the selected option:

$(this).find(':selected').data('id')

or

$(this).find(':selected').attr('data-id')

although the first method is preferred.

Jordan Brown
  • 13,603
  • 6
  • 30
  • 29
  • i mistakenly used attr() in my inital post, i meant data() but it returns 'undefined' for me. – userBG Dec 01 '11 at 17:34
  • 8
    I've just come across this and I am wondering if the first method is preferred due to performance reasons, or another reason? @JordanBrown – Clarkey Aug 19 '15 at 15:31
  • 2
    @Clarkey my guess would be that data() is faster than attr() because attr() has to do extra work to figure what type of attribute it is. Just a guess tho. – dev_willis Mar 19 '20 at 18:48
44

Try the following:

$('select').change(function(){
  alert($(this).children('option:selected').data('id'));
});

Your change subscriber subscribes to the change event of the select, so the this parameter is the select element. You need to find the selected child to get the data-id from.

Rich O'Kelly
  • 41,274
  • 9
  • 83
  • 114
  • 1
    As of 2016 `find()` is much faster than `children()` even in cases like this one where we only have a tree depth of 2. – Hafenkranich Oct 15 '16 at 14:56
19
document.querySelector('select').onchange = function(){   
   alert(this.selectedOptions[0].getAttribute('data-attr')); 
};
goto
  • 7,908
  • 10
  • 48
  • 58
  • Please always endeavor to support your posted code block with explanation and/or references (even if the solution is simple / "self-explanatory") on StackOverflow because not everyone is familiar with a given language's syntax / behavior / performance. – mickmackusa Apr 23 '18 at 01:10
13
$('#foo option:selected').data('id');
  • 1
    Please always endeavor to support your posted code block with explanation and/or references (even if the solution is simple / "self-explanatory") on StackOverflow because not everyone is familiar with a given language's syntax / behavior / performance. – mickmackusa Apr 23 '18 at 01:10
  • The OP does not have an `id` attribute on the select element (and doesn't need one because of the utility of `this`). – mickmackusa Apr 23 '18 at 01:27
  • this works with select2 library also – Mohamed Raza Dec 01 '21 at 18:08
13

Maybe a more elegant way

$('option:selected', this).data('id')
JJaun
  • 1,690
  • 2
  • 10
  • 16
10

Vanilla Javascript:

this.querySelector(':checked').getAttribute('data-id')
Arthur Ronconi
  • 2,290
  • 25
  • 25
  • Please always endeavor to support your posted code block with explanation and/or references (even if the solution is simple / "self-explanatory") on StackOverflow because not everyone is familiar with a given language's syntax / behavior / performance. – mickmackusa Apr 23 '18 at 01:10
  • 1
    Don't know why, but no jquery solution worked, this one did :-) – funder7 Apr 11 '22 at 13:20
8

You can use context syntax with this or $(this). This is the same effect as find().

$('select').change(function() {
    console.log('Clicked option value => ' + $(this).val());
    <!-- undefined console.log('$(this) without explicit :select => ' + $(this).data('id')); -->
    <!-- error console.log('this without explicit :select => ' + this.data('id')); -->
    console.log(':select & $(this) =>    ' + $(':selected', $(this)).data('id'));
    console.log(':select & this =>       ' + $(':selected', this).data('id'));
    console.log('option:select & this => ' + $('option:selected', this).data('id'));
    console.log('$(this) & find =>       ' + $(this).find(':selected').data('id'));
});
<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js"></script>
<select>
    <option data-id="1">one</option>
    <option data-id="2">two</option>
    <option data-id="3">three</option>
</select>

As a matter of microoptimization, you might opt for find(). If you are more of a code golfer, the context syntax is more brief. It comes down to coding style basically.

Here is a relevant performance comparison.

mickmackusa
  • 43,625
  • 12
  • 83
  • 136
5

this works for me

<select class="form-control" id="foo">
    <option value="first" data-id="1">first</option>
    <option value="second" data-id="2">second</option>
</select>

and the script

$('#foo').on("change",function(){
    var dataid = $("#foo option:selected").attr('data-id');
    alert(dataid)
});
Gericke
  • 2,109
  • 9
  • 42
  • 71
  • 1
    Please always endeavor to support your posted code block with explanation and/or references (even if the solution is simple / "self-explanatory") on StackOverflow because not everyone is familiar with a given language's syntax / behavior / performance. – mickmackusa Apr 23 '18 at 01:11
1

By using this you can get the text, value and data attribute.

<select name="your_name" id="your_id" onchange="getSelectedDataAttribute(this)">
    <option value="1" data-id="123">One</option>
    <option value="2" data-id="234">Two</option>
</select>

function getSelectedDataAttribute(event) {
    var selected_text = event.options[event.selectedIndex].innerHTML;
    var selected_value = event.value;
    var data-id = event.options[event.selectedIndex].dataset.id);    
}
0
 alert($(this).first().data('id'));
Code8525
  • 39
  • 3
  • 2
    Please read [answer] and [edit] your answer to contain an explanation as to why this code would actually solve the problem at hand. Always remember that you're not only solving the problem, but are also educating the OP and any future readers of this post – chrslg Jan 28 '23 at 02:18