Deselect selected options in select menu with multiple and optgroups - javascript

I want to be able to with a click of a link to be able to deselect all pre-selected options in a select menu with multiple select enable and with option groups.
Here is an example of the menu:
<select name="ddBusinessCategory" id="ddBusinessCategory" class="f1" style="width:280px;height:200px" multiple="multiple">
<option value="">Select One</option>
<optgroup label="Abrasives" style="background:#F5F5F5;border-bottom:1px #EEE solid">
<option value="4" selected="selected">Abrasives</option>
</optgroup>
<optgroup label="Abstracters" style="background:#F5F5F5;border-bottom:1px #EEE solid">
<option value="5">Abstracters</option>
</optgroup>
<optgroup label="Abuse Information & Treatment Centers" style="background:#F5F5F5;border-bottom:1px #EEE solid">
<option value="6" selected="selected">Abuse Information & Treatment Centers</option>
</optgroup>
<optgroup label="Accountants" style="background:#F5F5F5;border-bottom:1px #EEE solid">
<option value="7">Accountants</option>
<option value="2672">Certified Public Accountants - </option>
<option value="2673">Public Accountants - </option>
</optgroup>
<optgroup label="Accounting Services" style="background:#F5F5F5;border-bottom:1px #EEE solid">
<option value="8">Accounting Services</option>
</optgroup>
<optgroup label="Acoustical Materials - Wholesale & Manufacturers" style="background:#F5F5F5;border-bottom:1px #EEE solid">
<option value="9">Acoustical Materials - Wholesale & Manufacturers</option>
</optgroup>
</select>
You will see two are selected.. I want to be able to deselect these preselected ones.
DONT want to use jquery, just want to use javascript
Many thanks for your assistance.
neojakey

The following function should loop through all the options and unselect them.
HTML
clear
JAVASCRIPT
function clearSelected(){
var elements = document.getElementById("ddBusinessCategory").options;
for(var i = 0; i < elements.length; i++){
elements[i].selected = false;
}
}
EDIT:
I don't endorse putting the event handler directly on the element. If you have the option, give the element some type of id/name and bind the event handler in your JavaScript code.
EXAMPLE

Would it not be simpler to just use?:
document.getElementById("ddBusinessCategory").value = "";

You don't need any loops. The selectedIndex property "Sets or returns the index of the selected <option> element in the collection (starts at 0)".
Indexing starts at 0 so if you set it to -1 none are selected. (setting to 0 would leave the first option selected.)
function clearSelected(w){
document.getElementById(w).selectedIndex = -1;
}
clear

You could simplify the code from Chase with the javascript property "selectedOptions"
HTML
clear
JAVASCRIPT
function clearSelected(){
var elements = document.getElementById("ddBusinessCategory").selectedOptions;
for(var i = 0; i < elements.length; i++){
elements[i].selected = false;
}
}
In this case you do a loop with the already selected options and not all options.

If you are using jquery you can do (i know the person who asked this is expecting a js answer but this might help someone)
$('#someid').find($('option')).attr('selected',false)

If you don't care about < IE8:
var checkedElements = document.querySelectorAll("#ddBusinessCategory :checked");
​for(var i = 0, length = checkedElements.length; i < length; i++) {
checkedElements[i].selected = false;
}​
If you don't care about < IE9
Array.prototype.forEach.call(document.querySelectorAll("#ddBusinessCategory :checked"), function(el) { el.selected = false });
Use the answer from Chase if you want to support IE7, IE6, FF3 and earlier or feel it's easier to read.

If you only want to loop through only the selected options, I suggest a while loop.
var elements = document.getElementById("ddBusinessCategory").selectedOptions;
while (elements.length > 0)
{
elements[0].selected = false;
}
The answer by Michel Sahli will not work when there are multiple selections, because as you progress through the for loop the value of elements.length changes.
That said, the .selectedOptions attribute is a bit troublesome (see Is selectedOptions broken or...?) so probably not worth whatever tiny savings you get by only looping through selected options.

Once you select the option elements from the DOM in an object however you do that,
(I will pretend they all have a class name) just remove the attribute:
The Answer:
options = document.getElementsByClassName('optionsClassName');
for (let i = 0; i < options.length; i++) {
options[i].removeAttribute('selected');
}
The Reason: HTML reads to see if a selected attribute exists. You can just have "selected" as an attribute without any value, and it will assume that option is selected. So, it works if you remove the attribute. Selecting will insert a new "selected" attribute. No worry.

Related

Reset selected value from dropdown using jQuery

I am trying to clear selected value on a button click using jQuery.
$("#cityCode")[0].selectedIndex = 0;
This is working fine for a single selector, but if I target multiple selectors like this
$("#cityCode, #townCode")[0].selectedIndex = 0;
It works only for first ID. Can anyone help me to write fix syntax?
To clear all selected options from dropdown on a button click.
As you're selecting multiple elements you need to reset the selectedIndex on all of them, not the 0th element. To do that you can use an each() loop:
$("#cityCode, #townCode").each((i, el) => el.selectedIndex = 0);
Alternatively, if the first option in both dropdowns has an empty value, eg. <option value="">Please select</option>, then you can use the val() method which will implicitly loop for you:
$("#cityCode, #townCode").val('');
Use jQuery's .prop() method:
Set the selected option to 0 index
This is considered bad practice since the defaultSelected might not necessarily be the option at index 0. Such depends on which option had originally the selected HTML attribute set (see the other example). This is only OK -ish if you don't use such attribute on your Option elements.
$("#cityCode, #townCode").prop("selectedIndex", 0);
<select id="cityCode">
<option>111</option>
<option selected>222</option>
<option>333</option>
</select>
<select id="townCode">
<option>aaa</option>
<option selected>bbb</option>
<option>ccc</option>
</select>
<script src="https://cdnjs.cloudflare.com/ajax/libs/jquery/3.6.1/jquery.min.js"></script>
In vanilla JavaScript:
document.querySelectorAll("#cityCode, #townCode").forEach(elSelect => {
elSelect.selectedIndex = 0;
});
Reset option to original defaultSelected index
Notice that the above sets specifically the index to 0 (first option element), which might not be the original defaultSelected.
To account for this use:
$("#cityCode").val("333"); // just to force emulate some dynamic change
$("#townCode").val("ccc");
$("#cityCode, #townCode").prop("selectedIndex", function() {
const idx = [...this.options].findIndex((opt) => opt.defaultSelected);
return idx < 0 ? 0 : idx;
});
<select id="cityCode">
<option>111</option>
<option selected>222</option>
<option>333</option>
</select>
<select id="townCode">
<option>aaa</option>
<option selected>bbb</option>
<option>ccc</option>
</select>
<script src="https://cdnjs.cloudflare.com/ajax/libs/jquery/3.6.1/jquery.min.js"></script>
Reset form
If instead, you wish to reset the entire form use:
$("#someForm")[0].reset();
Don't use .val("")
as suggested in other answers... don't use .val(""). Here's why:
$("#cityCode, #townCode").val("");
<select id="cityCode">
<option>111</option>
<option selected>222</option>
<option>333</option>
</select>
<select id="townCode">
<option>aaa</option>
<option selected>bbb</option>
<option>ccc</option>
</select>
<script src="https://cdnjs.cloudflare.com/ajax/libs/jquery/3.6.1/jquery.min.js"></script>
Try this:
$("#cityCode, #townCode").each(function(){
$(this).selectedIndex = 0;
});

What is best way to select multiple html tags and their value to apply expression in Javascript?

I have a specialized e-commerce cart I built where the customer selects how many of rooms, floors, etc. from a table and then it calculates the value live.
Html table entries for each drop down option looks like this
<table>
<td><select onchange="calculateall()" id="roomsclear1" size="1">
<option value="0">0</option>
<option value="1">1</option>
<option value="2">2</option>
<option value="3">3</option>
<option value="4">4</option>
</select> </td>
</table>
<h1> Total:<h1> <p id="total"> Final Value goes here after calculation of all 20 options</p>
Each type of cleaning service unfortunately has a different price point so I tried this switch statement.
var selectedt = document.getElementsByTagName('select');
function calculateall() {
for (var i = 0; i < selectedt.length; ++i) {
var calcit = selectedt.options[selectedt[i].selectedIndex].value;
var typeid = selectedt[i].id;
switch (typeid) {
case 'roomsclean1':
calcit = calcit * 65;
break;
}
document.getElementById("total").innerHTML = calcit;
}
}
Questions:
I'm only getting a 0 or 1 value written to total in HTML no matter what option I select from the table. I assume I'm screwing up on the Javascript.
Is a switch statement the most efficient option? 20+ options each with different pricing per # of rooms selected
I put an example of the cart on a temporary page here(slow!):
52.11.14.57:9000/#
JSfiddle: https://jsfiddle.net/mvc1poad/
The ID in the example correspondes to carpet cleaning tabs: rooms(clean)
Edit: Rakesh_Kumar is correct, the issue is the lack of parseInt. Adding that should address the issue when calculating values.
You mentioned you can output the actual values (which I'd recommend since it will simplify your script slightly). Personally, I would wrap an element around your select element(s) and allow a change event to bubble up (rather than an inline event handler like calculateall - just cleans up your HTML).
Something like:
<form id="ourForm">
<select id="cleaning">
<option value="0">Select cleaning</option>
<option value="0">No cleaning</option>
<option value="10">Cleaning final day only</option>
<option value="50">Cleaning 5 days</option>
</select>
<!-- additional elements here -->
</form>
And a simple JS event listener like this:
document.forms[0].addEventListener('change', function(e) {
var i = 0,
query = this.querySelectorAll('select'),
len = query.length,
total = 0;
for(; i < len; i++) {
if (parseInt(query[i].value, 10) > 0) {
total += parseInt(query[i].options[query[i].selectedIndex].value, 10);
}
}
// Do something with total here
}, true);
Here's a demo fiddle: http://jsfiddle.net/sj9o6Lnb/
If you're interested in using a multiplier, you could create a map which you then multiply the values by. Something like:
var price_map {
rooms_clean: 65,
breakfast: 100
}
Which you then reference the price by an id (or some other attribute)
for(; i < len; i++) {
total += price_map[query[i].id] * parseInt(query[i].options[query[i].selectedIndex].value, 10);
}
http://jsfiddle.net/sj9o6Lnb/1/
Here's an updated fiddle based on your site (with the four options and clean/protect): http://jsfiddle.net/sj9o6Lnb/2/
And an edited fiddle that you created: https://jsfiddle.net/mvc1poad/1/ (this one here just calculates based on a data attribute, which you would need to add)
You have made a silly mistake, because of which you are not getting expected output.
Instead of doing like:
//selectedt is HTMLCollection having list of all elements with tag "select"
//& typeof calcit is String, which you need to make a number before multiplying with 65
var calcit = selectedt.options[selectedt[i].selectedIndex].value;
do,
var calcit = parseInt(selectedt[i].options[selectedt[i].selectedIndex].value);
And, apart from switch usage, what other approach you are thinking to take. For Obvious reasons, switch is more preferable than if-else.

Get index of select option in optgroup

If I have an option list like the below:
<select name="optionList" id="optionList">
<optgroup label="optgroup1">
<option value="1">1</option>
<option value="2">2</option>
<option value="3">3</option>
<option value="4">4</option>
</optgroup>
<optgroup label="optgroup2">
<option value="5">5</option>
<option value="6">6</option>
<option value="7">7</option>
<option value="8">8</option>
</optgroup>
</select>
I know I can access the selectedIndex using:
document.getElementById('optionList').selectedIndex;
If I use the above though the selected index of 5 will be 4, 6 will be 5, 7 will be 6, etc
How can I tell where a selected item in an optgroup is?
In summary I'd like to be able to query something and get back its position in the optgroup so that 5 would return 0, 6 would return 1 etc...
This is a slightly complex task, because there is no native way to do it. I'm going to answer according to current browser standards: it's possible to do it in older browsers, but it is more work.
var select = document.getElementById('optionList'), // the <select> element
selectedIndex = select.selectedIndex, // 0-based index of which element in the <select> is selected
selectedElement = select.options[selectedIndex], // DOM element selected
optGroup = selectedElement.parentNode, // <optgroup> element
optGroupOptions = optGroup.children, // <option> elements in the <optgroup>
positionInOptGroup = Array.prototype.indexOf.call(optGroupOptions, selectedElement); // the selected <option>'s position in the <optgroup>
(jsFiddle)
Note that this will not work if the browser does not support Element#children (i.e. IE <9). You will have to filter the childNodes collection into an array at test against that. Similarly, it requires Array#indexOf, which also didn't exist in IE <9.
with pure javascript
var element = document.getElementById('optionList');
console.log(element.options[element.selectedIndex].parentNode.label);
Try this:
function indexOf(select) {
var options = select.options;
var selectedOption = options.item(select.selectedIndex);
var nodes = selectedOption.parentNode.children;
for (var i = 0; i < nodes.length; ++i) {
if (nodes[i] === selectedOption) {
return i;
}
}
return -1;
}
indexOf(document.getElementById('optionList'));
Working sample: http://jsfiddle.net/49R7k/1/
jQuery crossbrowser solution:
$('#optionList option:selected').index();
preview
I know that this is an old question and implementations may have changed, but I found that simple jQuery solution within the selector change event, e.g.
$(document).on('change', ".cmilestoneTaskSelector", function(e)
{
alert($(this.options[this.selectedIndex]).index());
.....
Tested in both Firefox and Chrome.

How to update html SELECT options with javascript or jquery, using values from other SELECT's (within eric hynds's multiselect widget)

I'm using Eric Hynds's jQuery multiselect widget to display a list of employees in several different sections on the same screen. I have several different multiselects on the same page, some of which have the same employees.
If a user selects (or unselects) an employee in one multiselect, I need to update the others to reflect the same choices. I have 2 'optgroups' to consider as well, if possible, but those can be ignored for this purpose, unless it's relatively easy to handle.
The options could be refreshed with javascript or jquery, independent of the multiselect widget, and then the .refresh method could be called to update the widget. So, the solution to this may or may not use code from the widget to do the updating of the options.
Here are examples of two SELECTs and their options. Brian Jones appears in both. If Brian Jones is selected in the first example, how can I dynamically select him in the second example (and if possible, move him to the 'Assigned Employees' group)? Same goes for if he is un-selected.
<select id="empSelection_01" name="employee_01" multiple="multiple">
<optgroup label="Unassigned Employees">
<option value="42954">Smith, Joe</option>
<option value="30357">Jones, Brian</option>
</optgroup>
<optgroup label="Assigned Employees">
<option value="42900">Brown, Laura</option>
<option value="30399">Evans, Jessica</option>
</optgroup>
</select>
<select id="empSelection_02" name="employee_02" multiple="multiple">
<optgroup label="Unassigned Employees">
<option value="42954">Doe, Jane</option>
<option value="30357">Jones, Brian</option>
</optgroup>
<optgroup label="Assigned Employees">
<option value="42900">Hix, Carolyn</option>
<option value="30399">Evans, Jessica</option>
</optgroup>
</select>
Try like this fiddle
$('#empSelection_01').multiselect({click:function(e){
var isChecked = $(e.currentTarget).attr("checked")=="checked";
var labelFrom = isChecked ? 'Unassigned Employees' : 'Assigned Employees';
var labelTo = !isChecked ? 'Unassigned Employees' : 'Assigned Employees';
var el = $('#empSelection_02').children('[label="' + labelFrom + '"]').children('[value="' + e.currentTarget.value + '"]');
el.remove();
$('#empSelection_02').children('[label="' + labelTo + '"]').append(el);
if (isChecked) {
el.attr('selected', 'selected');
} else {
el.removeAttr('selected');
}
$('#empSelection_02').multiselect('refresh');
}});
It's example how you can manipulate with this plugin, but it's not enough to solve you problem. You neeed some logic, to take options into consideration, and indicate in which group options must be located, especially if many-to-many connections is possible.
I ended up using this JavaScript, which receives the ID of the SELECT that was just changed, and then uses values within that SELECT to process all other SELECT's on the screen:
function refreshEmps(currID){
var sel = document.getElementById(currID);
var opt = sel.options;
var checkedVals = new Array();
// save checked values ***************************
for (i=0; i<opt.length; i++){
if (opt[i].selected==true) {
checkedVals[checkedVals.length]=opt[i].value;
}
}
//update remaining SELECT's ***************************
var ddCounter = 0; //
while(document.getElementById("employeeDD_" + ddCounter)!=null) {
var sel2 = document.getElementById("employeeDD_" + ddCounter);
if (currID!=sel2.id) {
var opt2 = sel2.options;
for (i=0; i<opt2.length; i++){
for (j=0; j<checkedVals.length; j++) {
if(opt2[i].value==checkedVals[j]) {
opt2[i].disabled=true;
opt2[i].style.color = 'red';
}
}//end for
}
}//end if
ddCounter++;
}//end WHILE
$("select").multiselect('refresh');
}

recreate an array based on options selected

I need help solving a simple requirement.
<select id="my-select1">
<option value="1">This is option 1 ({myop1}|OP)</option>
<option value="2" selected>This is option 2 ({myop1}|OQ)</option>
<option value="3">This is option 3 ({myop1}|OR)</option>
</select>
<select id="my-select2">
<option value="1">This is option 1 ({myop2}|PP)</option>
<option value="2">This is option 2 ({myop2}|PQ)</option>
<option value="3" selected>This is option 3 ({myop2}|PR)</option>
</select>
<select id="my-select3">
<option value="1">This is option 1 ({myop3}|QP)</option>
<option value="2">This is option 2 ({myop3}|QQ)</option>
<option value="3" selected>This is option 3 ({myop3}|QR)</option>
</select>
See the HTML above, I want to recreate my array:
combo = ["abc-{myop1}-{myop2}", "def-{myop2}"];
INTO
combo = ["abc-OQ-PR", "def-PR"];
based on the selected options.
Another thing to note is that I cannot simply change the value of the options of the select box, meaning to say the HTML is somewhat as it is, if it would help, the only part i can restructure on that HTML is the text content between <option></option>
I'm not sure, but I'm already spending a couple of hrs just to solve this problem. Maybe due to my limited jQuery knowledge.
Please help. thanks
Get the selected values into an associative array:
var pattern = {};
var s = $('select option:selected').each(function(){
var m = /\((.*?)\|(.*)\)/.exec($(this).text());
pattern[m[1]] = m[2];
});
Then you can replace each place holder in each string in the array with the corresponding value:
combo = $.map(combo, function(e){
return e.replace(/\{.*?\}/g, function(m){
return pattern[m];
});
});
Demo: jsfiddle.net/C97ma/
Based on the information you provided I'm don't get it 100% I guess. But whatever you're trying to do, I guess jQuerys .map() and $.map() would help you here.
Like
var arr = $('select').find('option:selected').map(function(index, elem) {
return elem.textContent || elem.text;
}).get();
Demo: http://www.jsfiddle.net/4yUqL/78/
Within the callback you can modify/match the text in any way you want/need. In your case I could imagine you want to use a regular expression to match the selected strings and recreate those somehow.
I figure you're using javascript for combining those (it can be done with PHP also)..
You need references to your selects, e.g. :
<script type="text/javascript">
a=document.getElementById("myselect").options[1];
</script>
This will assign the 2nd option value from the 'myselect' select element to the variable 'a'
To begin with I would change the values in the select box like this:
<select id="my-select1">
<option value="OP">This is option 1 ({myop1}|OP)</option>
<option value="OQ" selected>This is option 2 ({myop1}|OQ)</option>
<option value="OR">This is option 3 ({myop1}|OR)</option>
</select>
<select id="my-select2">
<option value="PP">This is option 1 ({myop2}|PP)</option>
<option value="PQ">This is option 2 ({myop2}|PQ)</option>
<option value="PR" selected>This is option 3 ({myop2}|PR)</option>
</select>
<select id="my-select3">
<option value="QP">This is option 1 ({myop3}|QP)</option>
<option value="QQ">This is option 2 ({myop3}|QQ)</option>
<option value="QR" selected>This is option 3 ({myop3}|QR)</option>
</select>
Now to update your array:
var comboDef = ["abc-{myop1}-{myop2}", "def-{myop2}"];
var combo = ["abc-{myop1}-{myop2}", "def-{myop2}"];
function updateArray() {
combo = comboDef;
for (i in combo)
{
combo[i] = combo[i].replace("{myop1}",document.getElementById("my-select1").value);
combo[i] = combo[i].replace("{myop2}",document.getElementById("my-select2").value);
combo[i] = combo[i].replace("{myop3}",document.getElementById("my-select3").value);
}
}
Of course, this could be done better with proper arrays (if you gave your select boxes the same name you could iterate through them using document.getElementsByName()). The basic idea is the replace though which I trust is what you're looking for.

Categories