327

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,250
  • 9
  • 30
  • 37

9 Answers9

773

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
  • 12,933
  • 6
  • 29
  • 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
  • 1
    @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
42

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
  • 40,274
  • 9
  • 81
  • 111
  • 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
16
document.querySelector('select').onchange = function(){   
   alert(this.selectedOptions[0].getAttribute('data-attr')); 
};
goto
  • 7,454
  • 10
  • 46
  • 54
  • 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
9

Vanilla Javascript:

this.querySelector(':checked').getAttribute('data-id')
Arthur Ronconi
  • 2,032
  • 23
  • 21
  • 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
  • 37,596
  • 11
  • 75
  • 105
7
$('#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
7

Maybe a more elegant way

$('option:selected', this).data('id')
JJaun
  • 1,372
  • 2
  • 9
  • 15
4

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
  • 1,983
  • 6
  • 41
  • 68
  • 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);    
}