Get index of select option in optgroup - javascript

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.

Related

Jquery Create Number Of Input Elements based on select value

I would like to start by saying I am very new to jquery and javascript I rarely use it, however I now find myself in a position where I need to make use of it.
What I am trying to do
I am trying to let admin-user upload matches to db for a round in a competition, thus building the schedule for round X....hope that makes sense
What should happen
if user selects, as an example, 4 from the dropdown box 8 input fields should be created, thus allowing user to enter the 2 teams which will play in each round in each match.
I have tried to code this, (please dont laugh) but the logic and code is completely wrong, if anyone can be so kind to assist me with this problem it would be much appreciated, possibly allowing me to build from this in the future.
JFiddle
https://jsfiddle.net/leela89/zvss0f8L/#&togetherjs=RApSQ2E6Sr
Code
<select id="nrGames" name="nrGame">
<option value="1">1</option>
<option value="2">2</option>
<option value="3">3</option>
<option value="4">4</option>
<option value="5">5</option>
<option value="6">6</option>
<option value="7">7</option>
<option value="8">8</option>
<option value="9">9</option>
<option value="10">10</option>
</select>
<script type="text/javascript">
//create input element for nr games
$("#nrGames").change(function(){
var value = $(this).val;
var nr = 0;
while(nr < value){
$('#games').add('input');
nr++;
}
})
</script>
<!--APPEND INOUT TEXT -->
<div id="games">
</div>
Try to .append() the new elements into the target element,
$("#nrGames").change(function() {
var value = +$(this).val();
value *= 2;
var nr = 0;
var elem = $('#games').empty();
while (nr < value) {
elem.append($('<input>',{name : "whateverNameYouWant"}));
nr++;
}
});
Also .val() is a function not a property.
DEMO
Small update: Different elements for player in each team will be helpful
$("#nrGames").change(function() {
var value = +$(this).val();
var nr = 0;
var elem = $('#games').empty();
while (nr < value) {
elem.append($('<input>',{name : "Team1Player"+nr}));
elem.append($('<input>',{name : "Team2Player"+nr}));
nr++;
}
});

Javascript: dropdown, get first element value LIKE?

Given a dropdown with an unknown number of option elements:
<select id="ddlDropDown">
<option value="text1">Some text</option>
<option value="text2">Some text</option>
<option value="text3">Some text</option>
...
<option value="textN">Some text</option>
And given a textbox where I can type in a value:
<input type=text id="txtTextBox" onkeyup="selectDDL();"/>
And given the script function:
function selectDDL(){
var txtElem = document.getElementById("txtTextBox");
var ddlElem = document.getElementById("ddlDropDown");
var typedText = txtElem.value;
//magic happens here
}
How do I, using purely javascript, get select the first option matching LIKE the text in the text box without iterating through the entire collection?
That is to say, assume that I have 500 dropdown option elements with random values between 500 and 1500, how do I get and select the first option (in the list, not in order) that matches what the user has typed so far?
So if their were three items: 1030, 1012, and 1013 in the dropdown and the user types:
1: 1030 is selected.
10: 1030 is still selected
101: 1012 is selected
1013: 1013 is selected
Clarification: without iterating the collection and similar to jquery's ^= operator
You don't need jQuery to use ^=, just use querySelectorAll with the attribute prefix selector:
var texts = document.querySelectorAll("[value^='text']");
console.log(texts);
<script src="http://gh-canon.github.io/stack-snippet-console/console.min.js"></script>
<select id="ddlDropDown">
<option value="text1">Some text</option>
<option value="text2">Some text</option>
<option value="text3">Some text</option>
<option value="textN">Some text</option>
<option value="notText">123456</option>
</select>
You can use a starts with attribute selector. Only issue with the code is I am not escaping any of the special characters from the selector. So if the user enters in ' it will blow up.
document.querySelector("#x").addEventListener("keyup", function(){
//code to filter out the options
var txt = this.value;
var opts = document.querySelectorAll("#ddlDropDown option[value^='" + txt + "']");
//code to display the options for demo
var out = Array.prototype.slice.call( opts ).map(function (x) {return x.value});
document.querySelector("p").innerHTML = out.join("<br/>");
});
<select id="ddlDropDown">
<option value="text1">Some text</option>
<option value="text2">Some text</option>
<option value="text3">Some text</option>
<option value="text11">Some text</option>
<option value="text21">Some text</option>
<option value="text31">Some text</option>
</select>
<input type="textbox" id="x">
<p></p>
I would use the string#indexOf method to find out if there's a match.
function selectDDL() {
var txtElem = document.getElementById("txtTextBox");
var ddlElem = document.getElementById("ddlDropDown");
var typedText = txtElem.value;
var options = document.querySelectorAll("#ddlDropDown option");
var matches = [];
for (var i = 0; i < 3; i++) {
if (options[i].innerHTML.indexOf(typedText) == 0) {
matches.push(options[i]);
}
}
matches[0].setAttribute("selected", "selected");
}
Those who rely on a selector with [value^=...] will find an option by its value attribute, not by its text.
There is no CSS selector for selecting an option by its text. jQuery supports "has" and "contains", but uses iteration to implement those features.
Just for a fun alternative, but probably not advisable: innerHTML is slow and this will go wrong when the select tag has other tags inside than the options:
var html = ddlElem.innerHTML;
var idx = html.indexOf('>'+typedText);
ddlElem.selectedIndex = idx === -1
? -1
: html.substr(0, idx).match(/\<option/g).length - 1;

Drop down list to create an order, cannot select the same number in each drop down list

Good Day everyone,
Currently working on an application, inside the settings I have a list of drop down list that my clients can select. Those drop down list are to create an order in which they want those options to appear.
How can you make it, that they cannot select 2 times the same number, and if they do the "new" selection will go replace the "same number" with the old selection.
<select name="temporary-1">
<option value="1">1</option>
<option value="2">2</option>
<option value="3">3</option>
<option value="4">4</option>
</select>
<select name="temporary-2">
<option value="1">1</option>
<option value="2">2</option>
<option value="3">3</option>
<option value="4">4</option>
</select>
<select name="temporary-3">
<option value="1">1</option>
<option value="2">2</option>
<option value="3">3</option>
<option value="4">4</option>
</select>
I am currently using jQuery in my application, so what I was thinking is to compare each Drop Down on change, and if the same number exist already I would just switch both numbers.
Would it be a proper way? Or is there ways already to do this?
You might want to use the selectize.js library to implement your drop downs, it's located here: https://brianreavis.github.io/selectize.js/
Here's a solution that replaces the options with only ones that haven't been chosen in the other elements
var $selects = $('select.temp'),// added a common class to the elements
opts = $selects.first().html()
$selects.change(function(){
$selects.each(function(){
var otherValues = $selects.not(this).map(function(){
return this.value ? this.value : null;
}).get();
var currVal = this.value;
$(this).html(function(){
return $(opts).filter(function(){
return $.inArray(this.value, otherValues) === -1;
});
}).val(currVal);
});
});
Also requires having an option with no value in each
DEMO
I'm using a similar idea to charlietfl's solution, but I went a little bit of a different route . . . my code disables any options that have already been selected in a different dropdown. Like his, mine also requires that you have an option with no value (there are ways to avoid that, if needed, but, if you can add in a default like that, it makes the code much more simple).
HTML
<select name="temporary-1">
<option value="">-</option>
<option value="1">1</option>
<option value="2">2</option>
<option value="3">3</option>
<option value="4">4</option>
</select>
<select name="temporary-2">
<option value="">-</option>
<option value="1">1</option>
<option value="2">2</option>
<option value="3">3</option>
<option value="4">4</option>
</select>
<select name="temporary-3">
<option value="">-</option>
<option value="1">1</option>
<option value="2">2</option>
<option value="3">3</option>
<option value="4">4</option>
</select>
JS/jQuery
$("document").ready(function() {
$("select").on("change", disableOptions);
});
function disableOptions() {
var $allSelectInputs = $("select");
var sChangedSelectName = $(this).attr("name");
var $changedSelectOptions = $(this).find("option");
var sChangedSelectVal = $changedSelectOptions.filter(":selected").val();
for (i = 0; i < $changedSelectOptions.length; i++) {
if (!($($changedSelectOptions[i]).prop("disabled"))) {
for (j = 0; j < $allSelectInputs.length; j++) {
if ($($allSelectInputs[j]).attr("name") !== sChangedSelectName) {
var $currentSelectOption = $($($allSelectInputs[j]).find("option")[i]);
if (sChangedSelectVal !== "") {
if ($currentSelectOption.val() === sChangedSelectVal) {
$currentSelectOption.prop("disabled", true);
}
else {
$currentSelectOption.prop("disabled", false);
}
}
}
}
}
}
}
When an option is selected in one of the dropdowns, it will go through the other two and disable the value that matches the selection. By disabling them, instead of removing them, you can easily "reinstate" the optoins, if a new selection is made.
Ideally, you would be able to hide the options, instead of disabling them, but there are browser support issues when it comes to applying display: none; to <option> tags (glares at IE).
Thanks for your answers,
But those were not what I was looking for.
Here is how I did it:
First of, I already had a hidden field used for another purpose (which I forget to mention here).
$('.select_class').change(function () {
var $currentselect = $(this);
var $currentorder = $('input[name=' + $(this).attr('name') + '_current' + ']');
$("select[name^='select_order_']").each(function () {
var $checkcurrent = $('input[name=' + $(this).attr('name') + '_current' + ']');
if (!$(this).is(':disabled')) {
if($(this).prop('name') != $currentselect.prop('name')){
if($(this).val() == $currentselect.val()){
$(this).val($currentorder.val())
$checkcurrent.val($currentorder.val())
}
}
}
});
$currentorder.val($(this).val())
});
The $currentselect takes the field that was modified and keeps it as a variable to be used in the below sections
The $currentorder take the name of the .class_select and add _current (which becomes the hidden field with the current data.
For all the "select_order" I do the following checks:
Create the checkcurrent variable to modify it later if it is needed
Is it disabled, If it is just skip it
does the $currentselect value has the same value has the "select_order"
If it has the same value, change the current "select_order" with the $currentorder value and then allow the change to the $currentselect
change checkcurrent with the new value so the _current has the proper number for each

Deselect selected options in select menu with multiple and optgroups

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.

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