118

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;
}
0

28 Answers 28

155

A quick example with no jQuery:

// Return an array of the selected option values in the control.
// 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;
}
<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>

Sign up to request clarification or add additional context in comments.

5 Comments

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;
select is not the best variable name in JavaScript.
@TecBrat var options = select && select.options ensures that select is not undefined, before accessing its attributes.
I don't think the line with && makes much sense ... if selectis not defined getElementByIdwill 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—the code doesn't use getElementById, avoiding errors is generally considered a good idea. There are "better" ways of writing the code, the focus here was to show that selected options can be found by looping over the options and testing the selected property. Now a selector would likely be used to get a collection of options, however selectors only work on attributes not properties so looping to get the selected options is still required.
137

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;

1 Comment

This is perfect. Is there also a way to retrieve the labels or text instead of the values themselves?
90

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>

1 Comment

this works if the selected is in the options tag but did not work if changes on the form
82

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; 
});

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);

6 Comments

Alternatively, if you have the element: Array.from(element.querySelectorAll("option:checked"),e=>e.value);
Just FYI, it is faster to use the selectedOptions/options collection than to use querySelectorAll.
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);.
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.
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) });
|
47

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

5 Comments

You could use just reduce() method My implementation
If you can get reference to <select>, why not skip filter() step and just get reference to :checked children of <select> using querySelectorAll?
@Evgeny many ways to solve it. You should post your approach in a new answer.
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 it's a good question but I don't think efficiency matters much unless we're talking about hundreds or thousands of options.
43

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);

Comments

19

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

Comments

12

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

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

Comments

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);
}

Comments

11

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; }]
);

4 Comments

Isn't the functionality of the first one already in Javascript?
Ok, got it. But the first one can be shorter. Just select.selectedOptions.
That's a drawback of bare JS compared to using libraries. The selectedOptions property lacks in reliable browser support. 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.
There's no need to use apply. Use call and you can avoid having to pass an array of arguments.
9

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);

Comments

9

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>

Comments

8

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.

1 Comment

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'))
5

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
})

Comments

5

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

Comments

5

Here is an ES6 implementation:

value = Array(...el.options).reduce((acc, option) => {
  if (option.selected === true) {
    acc.push(option.value);
  }
  return acc;
}, []);

1 Comment

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.
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!

Comments

4

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.

Comments

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>

1 Comment

FormData is a Web APIs facility, btw. It didn't first occur to me :)
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>

Comments

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;
  }, []);
};

1 Comment

Array.prototype.filter would be a better option [].filter.call(ele.options, e => e.selected)
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
}

Comments

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; });
}

Comments

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;
};

Comments

0

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)

Comments

0

Simply use this single line of code: (without JQuery)

const category_ids = Array.from(document.querySelectorAll('#category_id option:checked')).map(option => option.value);
console.log('category_ids: ', category_ids);

Comments

0

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

JavaScript:

/**
* 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.

Comments

-1
  1. $('#application_student_groups option:selected') returns a collection of selected objects
  2. .toArray() returns the selected objects in an array
  3. And in map I return the option value (or you can return text) from the array.
$('#application_student_groups option:selected').toArray().map(item => item.value)

1 Comment

.map() is already given in a solution posted in 2020.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.