103

I have a <select> element with the multiple attribute. How can I get this element's selected values using JavaScript?

Here's what I'm trying:

function loopSelected() { 
    var txtSelectedValuesObj = document.getElementById('txtSelectedValues');
    var selectedArray = new Array();
    var selObj = document.getElementById('slct'); 
    var i;
    var count = 0;
    for (i=0; i<selObj.options.length; i++) { 
        if (selObj.options[i].selected) {
            selectedArray[count] = selObj.options[i].value;
            count++; 
        } 
    } 
    txtSelectedValuesObj.value = selectedArray;
}
Machavity
  • 30,841
  • 27
  • 92
  • 100
TKV
  • 2,533
  • 11
  • 43
  • 56

28 Answers28

142

No jQuery:

// Return an array of the selected opion values
// select is an HTML select element
function getSelectValues(select) {
  var result = [];
  var options = select && select.options;
  var opt;

  for (var i=0, iLen=options.length; i<iLen; i++) {
    opt = options[i];

    if (opt.selected) {
      result.push(opt.value || opt.text);
    }
  }
  return result;
}

Quick example:

<select multiple>
  <option>opt 1 text
  <option value="opt 2 value">opt 2 text
</select>
<button onclick="
  var el = document.getElementsByTagName('select')[0];
  alert(getSelectValues(el));
">Show selected values</button>
RobG
  • 142,382
  • 31
  • 172
  • 209
  • 2
    Thank you for this answer. Could you please step through it for me? I think I understand MOST of it, but what does `var options = select && select.options;` do? In my **inexperience**, I expected that to be `var options = select.options;` – TecBrat Jan 22 '14 at 20:13
  • 13
    `select` is not the best variable name in JavaScript. – VisioN Mar 05 '14 at 11:12
  • 6
    @TecBrat `var options = select && select.options` ensures that select is not undefined, before accessing its attributes. – Qwerty Aug 11 '15 at 11:23
  • 1
    I don't think the line with && makes much sense ... if `select`is not defined `getElementById`will return `null`. In this case, `options` will be null and error once you try to access to length property. But maybe I'm missing something? – Xen_mar Aug 28 '20 at 18:31
131

With jQuery, the usual way:

var values = $('#select-meal-type').val();

From the docs:

In the case of <select multiple="multiple"> elements, the .val() method returns an array containing each selected option;

Basj
  • 41,386
  • 99
  • 383
  • 673
Felix Kling
  • 795,719
  • 175
  • 1,089
  • 1,143
  • This is perfect. Is there also a way to retrieve the labels or text instead of the values themselves? – Cos Nov 26 '22 at 23:57
75

Actually, I found the best, most-succinct, fastest, and most-compatible way using pure JavaScript (assuming you don't need to fully support IE lte 8) is the following:

var values = Array.prototype.slice.call(document.querySelectorAll('#select-meal-type option:checked'),0).map(function(v,i,a) { 
    return v.value; 
});

UPDATE (2017-02-14):

An even more succinct way using ES6/ES2015 (for the browsers that support it):

const selected = document.querySelectorAll('#select-meal-type option:checked');
const values = Array.from(selected).map(el => el.value);
KyleFarris
  • 17,274
  • 5
  • 40
  • 40
  • 15
    Alternatively, if you have the element: ```Array.from(element.querySelectorAll("option:checked"),e=>e.value);``` – Someguynamedpie Apr 11 '18 at 04:37
  • 2
    Just FYI, it is faster to use the selectedOptions/options collection than to use querySelectorAll. – Adam Leggett Nov 07 '18 at 19:47
  • 7
    Thanks @AdamLeggett. For reference to those who don't know, that would change make @Someguynamedpie's code above to: `Array.from(element.selectedOptions).map(v=>v.value);`. – KyleFarris Nov 08 '18 at 20:45
  • It would, but see my answer below - it doesn't work at all on IE and has odd behavior in some older versions of Chrome and Firefox. If you don't care about performance, querySelectorAll or filtering element.options does get the job done. Also, you can do [].map.call() instead of using Array.from(), I don't know what impact this would have on performance but it certainly wouldn't be negative. – Adam Leggett Nov 08 '18 at 21:09
  • used `checked` This worked for me, on a multi select dropdown, but should work for all drop-downs as well `$(".multiple_select > option:checked").each(function(){ console.log(this.value) });` – Joviano Dias Aug 29 '19 at 13:48
  • This works in IE11: `var values = Array.prototype.slice.call(select.querySelectorAll('option:checked')).map(function(option){return option.value})` – Collin Anderson Nov 20 '19 at 18:30
64

You can use selectedOptions property

var options = document.getElementById('select-meal-type').selectedOptions;
var values = Array.from(options).map(({ value }) => value);
console.log(values);
<select id="select-meal-type" multiple="multiple">
    <option value="1">Breakfast</option>
    <option value="2" selected>Lunch</option>
    <option value="3">Dinner</option>
    <option value="4" selected>Snacks</option>
    <option value="5">Dessert</option>
</select>
Mr. Polywhirl
  • 42,981
  • 12
  • 84
  • 132
Tang Chanrith
  • 1,219
  • 12
  • 8
  • 5
    A native, no-fuss, non-jQuery answer. Thank you. – Andrew Schwartz Feb 22 '21 at 16:32
  • this is a fantastic answer super simple and concise and can even be reduced to a single line `let selectedOptions = Array.from(document.getElementById(selectElem).selectedOptions).map(({ value }) => value);` – d0rf47 Jan 25 '22 at 22:15
  • this works if the selected is in the options tag but did not work if changes on the form – Rana Nadeem Apr 09 '22 at 07:00
  • 1
    In 2023 this should be the accepted answer. Much cleaner and cross-compatible. Does not require jQuery or other convoluted steps. – Andrew Toups Jan 30 '23 at 19:08
45

ES6

[...select.options].filter(option => option.selected).map(option => option.value)

Where select is a reference to the <select> element.

To break it down:

  • [...select.options] takes the Array-like list of options and destructures it so that we can use Array.prototype methods on it (Edit: also consider using Array.from())
  • filter(...) reduces the options to only the ones that are selected
  • map(...) converts the raw <option> elements into their respective values
Rick Viscomi
  • 8,180
  • 4
  • 35
  • 50
  • 5
    Nice functional implementation :) – roadev Nov 22 '16 at 14:27
  • You could use just reduce() method [My implementation](https://stackoverflow.com/a/44574936/4725218) – To_wave Jun 15 '17 at 19:00
  • If you can get reference to using querySelectorAll? – Evgeny Jul 30 '17 at 01:00
  • 2
    @Evgeny many ways to solve it. You should post your approach in a new answer. – Rick Viscomi Jul 31 '17 at 21:41
  • 1
    This code looks much nicer than the ugly for loop over `options.length`. But is `[...select.options]` efficient in modern JS? Doesn't this iterate over whole collection three times? (i.e. first to build an array from options, second to filter, third to map) where you could do it in one go with ugly for loop – Anentropic Dec 06 '17 at 17:11
  • 2
    @Anentropic it's a good question but I don't think efficiency matters much unless we're talking about hundreds or thousands of options. – Rick Viscomi Apr 30 '18 at 00:20
42

If you wanna go the modern way, you can do this:

const selectedOpts = [...field.options].filter(x => x.selected);

The ... operator maps iterable (HTMLOptionsCollection) to the array.

If you're just interested in the values, you can add a map() call:

const selectedValues = [...field.options]
                     .filter(x => x.selected)
                     .map(x => x.value);
Tomáš Zato
  • 50,171
  • 52
  • 268
  • 778
28

Check-it Out:

HTML:

<a id="aSelect" href="#">Select</a>
<br />
<asp:ListBox ID="lstSelect" runat="server"  SelectionMode="Multiple" Width="100px">
    <asp:ListItem Text="Raj" Value="1"></asp:ListItem>
    <asp:ListItem Text="Karan" Value="2"></asp:ListItem>
    <asp:ListItem Text="Riya" Value="3"></asp:ListItem>
    <asp:ListItem Text="Aman" Value="4"></asp:ListItem>
    <asp:ListItem Text="Tom" Value="5"></asp:ListItem>
</asp:ListBox>

JQUERY:

$("#aSelect").click(function(){
    var selectedValues = [];    
    $("#lstSelect :selected").each(function(){
        selectedValues.push($(this).val()); 
    });
    alert(selectedValues);
    return false;
});

CLICK HERE TO SEE THE DEMO

Sukhjeevan
  • 3,074
  • 9
  • 46
  • 89
  • 3
    Not a fan - the "HTML" isn't HTML (readable, but not HTML), and the answer requires adding JQuery as a dependency. – Iiridayn Dec 29 '17 at 23:55
18

First, use Array.from to convert the HTMLCollection object to an array.

let selectElement = document.getElementById('categorySelect')
let selectedValues = Array.from(selectElement.selectedOptions)
        .map(option => option.value) // make sure you know what '.map' does

// you could also do: selectElement.options
Hassan
  • 946
  • 8
  • 6
12

suppose the multiSelect is the Multiple-Select-Element, just use its selectedOptions Property:

//show all selected options in the console:

for ( var i = 0; i < multiSelect.selectedOptions.length; i++) {
  console.log( multiSelect.selectedOptions[i].value);
}
Shadow The GPT Wizard
  • 66,030
  • 26
  • 140
  • 208
KAFFEECKO
  • 173
  • 1
  • 2
  • 10
11

$('#select-meal-type :selected') will contain an array of all of the selected items.

$('#select-meal-type option:selected').each(function() {
    alert($(this).val());
});

John Conde
  • 217,595
  • 99
  • 455
  • 496
10

Pretty much the same as already suggested but a bit different. About as much code as jQuery in Vanilla JS:

selected = Array.prototype.filter.apply(
  select.options, [
    function(o) {
      return o.selected;
    }
  ]
);

It seems to be faster than a loop in IE, FF and Safari. I find it interesting that it's slower in Chrome and Opera.

Another approach would be using selectors:

selected = Array.prototype.map.apply(
    select.querySelectorAll('option[selected="selected"]'),
    [function (o) { return o.value; }]
);
uKolka
  • 36,422
  • 4
  • 33
  • 44
  • Isn't the functionality of the first one already in Javascript? – Arlen Beiler Mar 07 '16 at 16:28
  • 1
    Ok, got it. But the first one can be shorter. Just `select.selectedOptions`. – Arlen Beiler Mar 07 '16 at 16:34
  • 1
    That's a drawback of bare JS compared to using libraries. The selectedOptions property lacks in [reliable browser support](http://stackoverflow.com/questions/10711767/is-selectedoptions-broken-or). Library like jQuery will hide that from you. A lot has changed since 2013 but a quick google shows that people still have issues with selectedOptions. – uKolka Mar 07 '16 at 20:19
  • There's no need to use `apply`. Use `call` and you can avoid having to pass an array of arguments. – Unmitigated Oct 04 '22 at 17:50
8

Update October 2019

The following should work "stand-alone" on all modern browsers without any dependencies or transpilation.

<!-- display a pop-up with the selected values from the <select> element -->

<script>
 const showSelectedOptions = options => alert(
   [...options].filter(o => o.selected).map(o => o.value)
 )
</script>

<select multiple onchange="showSelectedOptions(this.options)">
  <option value='1'>one</option>
  <option value='2'>two</option>
  <option value='3'>three</option>
  <option value='4'>four</option>
</select>
Fergie
  • 5,933
  • 7
  • 38
  • 42
7

If you need to respond to changes, you can try this:

document.getElementById('select-meal-type').addEventListener('change', function(e) {
    let values = [].slice.call(e.target.selectedOptions).map(a => a.value));
})

The [].slice.call(e.target.selectedOptions) is needed because e.target.selectedOptions returns a HTMLCollection, not an Array. That call converts it to Array so that we can then apply the map function, which extract the values.

adlr0
  • 758
  • 9
  • 13
  • 1
    Sadly this won't work everywhere, turns out IE11 does not have the field selectedOptions. The following does work however: `Array.prototype.slice.call(field.querySelectorAll(':checked'))` – Robin Goupil Jul 17 '17 at 09:53
7

Check this:

HTML:

<select id="test" multiple>
<option value="red" selected>Red</option>
<option value="rock" selected>Rock</option>
<option value="sun">Sun</option>
</select>

Javascript one line code

Array.from(document.getElementById("test").options).filter(option => option.selected).map(option => option.value);
Yaseen Ahmad
  • 1,807
  • 5
  • 25
  • 43
Krish K
  • 96
  • 1
  • 2
4

Try this:

$('#select-meal-type').change(function(){
    var arr = $(this).val()
});

Demo

$('#select-meal-type').change(function(){
  var arr = $(this).val();
  console.log(arr)
})
<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js"></script>
<select id="select-meal-type" multiple="multiple">
  <option value="1">Breakfast</option>
  <option value="2">Lunch</option>
  <option value="3">Dinner</option>
  <option value="4">Snacks</option>
  <option value="5">Dessert</option>
</select>

fiddle

Mosh Feu
  • 28,354
  • 16
  • 88
  • 135
Ram
  • 143,282
  • 16
  • 168
  • 197
4

if you want as you expressed with breaks after each value;

$('#select-meal-type').change(function(){
    var meals = $(this).val();
    var selectedmeals = meals.join(", "); // there is a break after comma

    alert (selectedmeals); // just for testing what will be printed
})
ewroman
  • 625
  • 6
  • 14
4

Here is an ES6 implementation:

value = Array(...el.options).reduce((acc, option) => {
  if (option.selected === true) {
    acc.push(option.value);
  }
  return acc;
}, []);
To_wave
  • 504
  • 1
  • 7
  • 17
  • This works great. It's interesting to note that because `element.options` is a live collection, it cannot be reduced. It must first be converted to an Array as seen in the above answer. – Brandon Jun 15 '17 at 18:57
4

Building on Rick Viscomi's answer, try using the HTML Select Element's selectedOptions property:

let txtSelectedValuesObj = document.getElementById('txtSelectedValues');
[...txtSelectedValuesObj.selectedOptions].map(option => option.value);

In detail,

  • selectedOptions returns a list of selected items.
  • Specifically, it returns a read-only HTMLCollection containing HTMLOptionElements.
  • ... is spread syntax. It expands the HTMLCollection's elements.
  • [...] creates a mutable Array object from these elements, giving you an array of HTMLOptionElements.
  • map() replaces each HTMLObjectElement in the array (here called option) with its value (option.value).

Dense, but it seems to work.

Watch out, selectedOptions isn't supported by IE!

Kevin W Matthews
  • 722
  • 6
  • 19
3

Something like the following would be my choice:

let selectElement = document.getElementById('categorySelect');
let selectedOptions = selectElement.selectedOptions || [].filter.call(selectedElement.options, option => option.selected);
let selectedValues = [].map.call(selectedOptions, option => option.value);

It's short, it's fast on modern browsers, and we don't care whether it's fast or not on 1% market share browsers.

Note, selectedOptions has wonky behavior on some browsers from around 5 years ago, so a user agent sniff isn't totally out of line here.

TessellatingHeckler
  • 27,511
  • 4
  • 48
  • 87
Adam Leggett
  • 3,714
  • 30
  • 24
3

You can get as an array the values from the <select> at the submit of the form as this example :

const form = document.getElementById('form-upload');

form.addEventListener('change', (e) => {
    const formData = new FormData(form);
    const selectValue = formData.getAll('pets');
    console.log(selectValue);
})
<form id="form-upload">
  <select name="pets" multiple id="pet-select">
      <option value="">--Please choose an option--</option>
      <option value="dog">Dog</option>
      <option value="cat">Cat</option>
      <option value="hamster">Hamster</option>
      <option value="parrot">Parrot</option>
      <option value="spider">Spider</option>
      <option value="goldfish">Goldfish</option>
  </select>
</form>
  • [FormData](https://developer.mozilla.org/en-US/docs/Web/API/FormData) is a [Web APIs](https://developer.mozilla.org/en-US/docs/Web/API) facility, btw. It didn't first occur to me :) – Skj Sep 30 '22 at 17:33
2

You Can try this script

     <!DOCTYPE html>
    <html>
    <script>
    function getMultipleSelectedValue()
    {
      var x=document.getElementById("alpha");
      for (var i = 0; i < x.options.length; i++) {
         if(x.options[i].selected ==true){
              alert(x.options[i].value);
          }
      }
    }
    </script>
    </head>
    <body>
    <select multiple="multiple" id="alpha">
      <option value="a">A</option>
      <option value="b">B</option>
      <option value="c">C</option>
      <option value="d">D</option>
    </select>
    <input type="button" value="Submit" onclick="getMultipleSelectedValue()"/>
    </body>
    </html>
Pankaj Chauhan
  • 1,623
  • 14
  • 12
2

You can use [].reduce for a more compact implementation of RobG's approach:

var getSelectedValues =  function(selectElement) {
  return [].reduce.call(selectElement.options, function(result, option) {
    if (option.selected) result.push(option.value);
    return result;
  }, []);
};
Community
  • 1
  • 1
rouan
  • 5,339
  • 6
  • 22
  • 36
2

My template helper looks like this:

 'submit #update': function(event) {
    event.preventDefault();
    var obj_opts = event.target.tags.selectedOptions; //returns HTMLCollection
    var array_opts = Object.values(obj_opts);  //convert to array
    var stray = array_opts.map((o)=> o.text ); //to filter your bits: text, value or selected
    //do stuff
}
Steve Taylor
  • 412
  • 1
  • 4
  • 11
1

Same as the earlier answer but using underscore.js.

function getSelectValues(select) {
    return _.map(_.filter(select.options, function(opt) { 
        return opt.selected; }), function(opt) { 
            return opt.value || opt.text; });
}
F. P. Freely
  • 1,026
  • 14
  • 24
1

Works everywhere without jquery:

var getSelectValues = function (select) {
    var ret = [];

    // fast but not universally supported
    if (select.selectedOptions != undefined) {
        for (var i=0; i < select.selectedOptions.length; i++) {
            ret.push(select.selectedOptions[i].value);
        }

    // compatible, but can be painfully slow
    } else {
        for (var i=0; i < select.options.length; i++) {
            if (select.options[i].selected) {
                ret.push(select.options[i].value);
            }
        }
    }
    return ret;
};
Paul Cuddihy
  • 477
  • 6
  • 12
1

Here ya go.

const arr = Array.from(el.features.selectedOptions) //get array from selectedOptions property
const list = [] 
arr.forEach(item => list.push(item.value)) //push each item to empty array
console.log(list)
0
$('#application_student_groups option:selected').toArray().map(item => item.value)
Maxime Chevallier
  • 277
  • 1
  • 4
  • 14
  • 3
    Thanks for the answer. It would be great, if you could add a bit of explanation, how this is working and why you think, this is the best solution. Thanks! – Stephan Weinhold Jan 17 '21 at 07:09
  • 1) $('#application_student_groups option:selected') return collection of selected object 2) .toArray() return the selected objects in array 3) and in map I return the option value (or you can return text) from the array we cannot judge a solution a best until we get a solution in the way we work. this is best solution for me as it works the way I work. hope you understand – Sahil Azim Jan 18 '21 at 08:26
0

You can create your own function like this and use it everywhere

Pure JS

/**
* Get values from multiple select input field
* @param {string} selectId - the HTML select id of the select field
**/
function getMultiSelectValues(selectId) {
 // get the options of select field which will be HTMLCollection
 // remember HtmlCollection and not an array. You can always enhance the code by
 // verifying if the provided select is valid or not
  var options = document.getElementById(selectId).options; 
    var values = [];
    
   // since options are HtmlCollection, we convert it into array to use map function on it
    Array.from(options).map(function(option) {
        option.selected ? values.push(option.value) : null
    })

    return values;
}

you can get the same result using jQuery in a single line

$('#select_field_id').val()

and this will return the array of values of well.

Dharman
  • 30,962
  • 25
  • 85
  • 135
Koushik Das
  • 9,678
  • 3
  • 51
  • 50