Remove more than 1 select option using JavaScript - javascript

I have 3 columns of HTML selection fields which need to load otions dependent on the previous selection fields.
Selection in column 2 values will be dependant on selected value in column 1 selection. I have this raw JavaScript below which add 2 selection options to a an HTML select filed and then removes 2 based on the select value in selection 1.
My problem is that the part that removes the 2 selection field options is not removing both options but instead removes 1 of them.
Demo: http://jsfiddle.net/jasondavis/croh2nj8/3/
I realize some of this uses jQuery but the goal is to use raw JS without jQuery for this part in question....
$(document).ready(function() {
$("#action").change(function() {
var el = $(this) ;
var selectAttributeEl = document.getElementById('action-attribute');
if(el.val() === "form" ) {
var option = document.createElement('option');
option.text = 'Name';
var option2 = document.createElement('option');
option2.text = 'ActionURL';
selectAttributeEl.add(option);
selectAttributeEl.add(option2);
}else if(el.val() === "link" ) {
for (var i=0; i<selectAttributeEl.length; i++){
if (selectAttributeEl.options[i].value == 'Name'){
selectAttributeEl.remove(i);
}else if(selectAttributeEl.options[i].value == 'ActionURL'){
selectAttributeEl.remove(i);
}
}
}
});
});

The problem is in the for loop where you loop through the selectobject.options. When the first if condition is true, you mutate selectobject.options by removing the Name option. On the next iteration of the loop selectobject.options[i] now returns undefined.
Let's walk through the for loop to demonstrate:
i is 0, corresponding to option ID, nothing happens.
i is 1, corresponding to option Class, nothing happens.
i is 2, corresponding to option Name, the if statement is valid and it removes the Name option. Now selectobject.options has length of 3.
i is 3, which corresponds to undefined. That is, selectobject.options[3] is undefined since the previous iteration of the loop removed an item from selectobject.options.
One possible solution, in the if and else statements you could reset i back one, with i--. Here's an updated jsFiddle. Another option is too loop through selectobject.options backwards, as mutating the latter items won't effect the counter as it moves to the former items.
There are other ways to correct this as well, like creating a new options array based on the values you want to keep in the options, then loading it the new options into the select.

As I stated, you're getting the issue, very simply, because the for loop is started from index 0 and working your way up. When you remove an element, you remove it from the NodeList of options. Easiest way I know of is to start from the end of the node list and work your way to node number 0.
$(document).ready(function() {
$("#action").change(function() {
var el = $(this);
if (el.val() === "form") {
//$("#action-attribute").append(' <option value="Name">Name</option>');
//$("#action-attribute").append(' <option value="ActionURL">ActionURL</option>');
var x = document.getElementById('action-attribute');
var option = document.createElement('option');
option.text = 'Name';
var option2 = document.createElement('option');
option2.text = 'ActionURL';
x.add(option);
x.add(option2);
} else if (el.val() === "link") {
//$("#action-attribute option:last-child").remove() ;
var selectobject = document.getElementById("action-attribute");
var remove_array = ['Name', 'ActionURL'];
for (var i = selectobject.options.length - 1; i >= 0; i--) {
if (remove_array.indexOf(selectobject.options[i].value) != -1) {
selectobject.removeChild(selectobject.options[i]);
}
}
}
});
});
<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js"></script>
When :
<select id="action" name="action">
<option value="link">Link Clicked</option>
<option value="form">Form Submitted</option>
</select>
with:
<select id="action-attribute" name="action-attribute">
<option>ID</option>
<option>Class</option>
</select>

May I propose a different approach? Instead of maintaining the state of the menu by removing elements that shouldn't be there, blow away the menu option tags entirely and replace.
$(document).ready(function() {
var options = {
link: ['ID', 'Class']
},
dependentMenu = document.getElementById('action-attribute');
options.form = options.link.concat(['Name', 'ActionURL']);
$("#action").change(function() {
var el = $(this);
while (dependentMenu.firstChild) {
dependentMenu.removeChild(dependentMenu.firstChild);
}
options[el.val()].forEach(function(value) {
var option = document.createElement('option');
option.text = value;
dependentMenu.add(option);
});
});
});
<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js"></script>
When :
<select id="action" name="action">
<option value="link">Link Clicked</option>
<option value="form">Form Submitted</option>
</select>
with:
<select id="action-attribute" name="action-attribute">
<option>ID</option>
<option>Class</option>
</select>

Related

How to populate select options from an array based on a select value?

Trying to get my second select element's options to populate from an array based on the value of the first select element. I can't seem to understand why it only populates the items from the array of the first select element. I know the appendChild is causing the items to keep tacking on at the need, but I've tried to clear the variables, but it seems the option elements that were created stay.
Any help would be great, thanks!
<select id="makeSelect" onChange="modelAppend()">
<option value="merc">Mercedes</option>
<option value="audi">Audi</option>
<option value="bmw">BMW</option>
</select>
<select id="modelSelect">
</select>
<script>
var audiModels = ["TT", "R8", "A4", "A6"]; //audimodels
var mercModels = ["C230", "B28", "LTX",]; //mercmodels
var bmwModels = ["328", "355", "458i",]; //bmwmodels
var selectedMake = document.getElementById("makeSelect"); //grabs the make select
var selectedModel = document.getElementById("modelSelect"); //grabs the model select
var appendedModel = window[selectedMake.value + "Models"]; // appends "Models" to selectedMake.value and converts string into variable
function modelAppend() {
for (var i = 0; i < appendedModel.length; i ++) { // counts items in model array
var models = appendedModel[i]; // // sets "models" to count of model array
var modelOptions = document.createElement("option"); //create the <option> tag
modelOptions.textContent = models; // assigns text to option
modelOptions.value = models; // assigns value to option
selectedModel.appendChild(modelOptions); //appeneds option tag with text and value to "modelSelect" element
}
}
</script>
This line is fishy:
var appendedModel = window[selectedMake.value + "Models"];
You need to get the element when the value has changed, not on page load. Then you need to remove the options on change too, or you will get a very long list if the user selects multiple times. Use an object to store the arrays, that makes it much easier to access them later. Also better use an event listener instead of inline js (though that's not the main problem here).
Try below code:
let models = {
audiModels: ["TT", "R8", "A4", "A6"],
mercModels: ["C230", "B28", "LTX"],
bmwModels: ["328", "355", "458i"]
}
document.getElementById('makeSelect').addEventListener('change', e => {
let el = e.target;
let val = el.value + 'Models';
let appendTo = document.getElementById('modelSelect');
Array.from(appendTo.getElementsByTagName('option')).forEach(c => appendTo.removeChild(c));
if (!models[val] || !Array.isArray(models[val])) {
appendTo.style.display = 'none';
return;
}
models[val].forEach(m => {
let opt = document.createElement('option');
opt.textContent = opt.value = m;
appendTo.appendChild(opt);
});
appendTo.style.display = '';
});
<select id="makeSelect">
<option value=""></option>
<option value="merc">Mercedes</option>
<option value="audi">Audi</option>
<option value="bmw">BMW</option>
</select>
<select id="modelSelect" style="display:none">
</select>

HTML Select control behavior

I am trying to make an HTML Select control display a different set of strings when clicked (or opened) than what is displayed after an item is selected. For example, when opened I want to see "one", two", "three" displayed as choices. But if the user selects two, I want "2" to be displayed as the selected item. My onclick handler reloads the Select options list with the long version of the strings and the onchange handler repopulates the control with the short strings and then re-selects the selected item. This works in Firefox, but not in IE, Safari nor Chrome. It's been almost 10 years since I last had the pleasure of coding in JavaScript. Any help would be appreciated. Here's my code:
var selectedIndex = -1;
function onChanged() {
//once selected, replace verbose with terse forms
var myList = document.getElementById("myList");
selectedIndex = myList.selectedIndex;
var optionArray = ["One|1", "Two|2", "Three|3"];
myList.options.length = 0;
for (var option in optionArray) {
var pair = optionArray[option].split("|");
var newOption = document.createElement("option");
newOption.value = pair[1];
newOption.innerHTML = pair[1];
myList.options.add(newOption);
}
myList.selectedIndex = selectedIndex;
}
function onClicked() {
var myList = document.getElementById("myList");
var optionArray = ["1|One", "2|Two", "3|Three"];
myList.options.length = 0;
for (var option in optionArray) {
var pair = optionArray[option].split("|");
var newOption = document.createElement("option");
newOption.value = pair[1];
newOption.innerHTML = pair[1];
myList.options.add(newOption);
}
if (selectedIndex > -1)
myList.selectedIndex = selectedIndex;
}
<select id="myList" onchange="onChanged()" onclick="onClicked()">
<option value="1">1</option>
<option value="2">2</option>
<option value="3">3</option>
</select>
An alternate approach would be to have each option store the full version of the text, and only change the displayed text of the selected item to the abbreviated version upon selection.
(function() {
var valueMap = {
"1": "One (1)",
"2": "Two (2)",
"11": "Eleven (11)",
"ITAR": "International Traffic in Arms Regulation (ITAR)",
"ACA": "Affordable Care Act (ACA)",
"FUBAR": "Fluffed Up Beyond All Recognition (FUBAR)"
};
var myList = document.getElementById("myList");
for (var prop in valueMap) { // populate the dropdown from our object
var opt = document.createElement("option");
opt.value = prop;
opt.text = valueMap[prop];
myList.add(opt);
}
myList.selectedIndex = -1; // nothing selected by default
myList.addEventListener("change", function() {
this.options[this.selectedIndex].text = this.options[this.selectedIndex].value;
this.blur();
});
myList.addEventListener("mousedown", function() {
if (this.selectedIndex > -1) {
var newValue = valueMap[this.options[this.selectedIndex].value];
if (this.options[this.selectedIndex].text !== newValue) {
this.options[this.selectedIndex].text = newValue;
}
}
});
})();
<select id="myList" style="width:6em"></select>
This gets you most of the way there, but still has the annoying problem that #hopkins-matt alluded to; namely that if the user opens the drop-down list and either selects the already selected item or moves off of the list without selecting anything, the selection will retain the long version of the text.
The other downside to this approach is that you need to specify the select element's width to keep it from expanding to the maximum length of its hidden option elements.
It's a timing issue.
Change:
<select id="myList" onchange="onChanged()" onclick="onClicked()">
to:
<select id="myList" onchange="onChanged()" onmousedown="onClicked()">
If the user opens the list and moves off the list without clicking, the list will not revert to original unless you call onChanged() on onmouseout as well.
<select id="myList" onchange="onChanged()" onmousedown="onClicked()" onmouseout="onChanged()">
Update: To achieve the best cross browser (onfocus is required for FF, but breaks IE) support without browser sniffing us this combination:
<select id="myList" onchange="onChanged()" onblur="onChanged()" onfocus="onClicked()" onmousedown="onClicked()">
This will also correct the second selection of the same event, but only after the user clicks away from the element.
Update:
Solved... I think.
I rewrote the function you were using to change the options. IE was not firing onchange due to you removing all the option elements and adding new option elements. Which was causing IE to not be able to reference if the user had changed the selection index. The function now just modifies the value and innerHTML of the current option elements. I am using browser sniffing to eliminate the onmouseout call for FF. FireFox was calling onmouseout if you moved the cursor to the dropdown menu. This does cause a side effect in FF. If the user selects the same option in FF, the options do not return to the original state until the onblur is fired.
Demo: http://jsfiddle.net/hopkins_matt/3m1syk6c/
JS:
function changeOptions() {
var selectedIndex = -1;
var click = 0;
var myList = document.getElementById("myList");
var optionArray = ["One|1", "Two|2", "Three|3"];
var fireFox = /Firefox/i.test(navigator.userAgent);
console.log(fireFox);
if (fireFox == false) {
myList.onmouseout=function(){changeList(false)};
}
myList.onblur=function(){changeList(false)};
myList.onchange=function(){changeList(false)};
myList.onmousedown=function(){changeList(true)};
function changeList(listOpen) {
var isListOpen = listOpen;
if (isListOpen == true) {
for (i = 0; i < myList.options.length; i++) {
var pair = optionArray[i].split("|");
myList.options[i].value = pair[0];
myList.options[i].innerHTML = pair[0];
}
}
if (isListOpen == false) {
for (i = 0; i < myList.options.length; i++) {
var pair = optionArray[i].split("|");
myList.options[i].value = pair[1];
myList.options[i].innerHTML = pair[1];
}
}
}
}
changeOptions();
HTML:
<select id="myList">
<option value="1">1</option>
<option value="2">2</option>
<option value="3">3</option>
</select>

Replace option code with another code by using option index

I have a dropdown list
<select name="answers[0][]">
<option value="0" >Beredskap</option>
<option value="1" >Förbundsledning</option>
<option value="2" >Förbundsledning stab</option>
<option value="3" >Ekonomiavdelningen</option>
</select>
What i am seeking for is to get the value getElementsByTagName('select')[1] and then replace it with
<option value="1" disabled >Förbundsledning</option>
the reason for it is that the list is auto generated so i need to modify the html output instead.
what i have sofar that does not work is :
document.getElementsByTagName('select')[0]
.innerHTML.replace('<option value="1" disabled>apple</option>')
The option with the value 1 happens to be at index 1 in your code, should that always be the case other answers than this one will apply.
In the case where you don't know the order of the generated options and thus don't know the index of the option you want to change, it depends on whether you want to change the text based on the value or the original text.
You could do this:
var options = document.getElementsByTagName("option");
for(var e = 0; e < options.length; e++) {
//change by text
if (options[e].text == "Apple") {
options[e].text = "Förbundsledning";
}
//change by value
if (options[e].value == "1") {
options[e].text = "Förbundsledning";
}
}
you could use jQuery and selectors to find your list box $('#myListBox').val();
you can easily change the value by $('#myListBox').val("new value");
You can also easily iterate over the list of options and do whatever you wish.
$("#id option").each(function()
{
// add $(this).val() to your list
});
How about this ?
var sel = document.getElementsByTagName('select')[0];
sel.innerHTML = sel.innerHTML.replace('Förbundsledning', 'apple');
http://jsfiddle.net/VxhvF/
use function ;
function select_text_replace(option_text, replace_text) {
var el = document.getElementsByTagName('select')[0];
el.innerHTML = el.innerHTML.replace(option_text, replace_text);
};
select_text_replace("Förbundsledning", "apple");
select_text_replace("Ekonomiavdelningen", "apple2");
see sample: http://jsfiddle.net/sm94N/
document.getElementsByTagName('select')[0].options[1].text="apple"
[1] is index of your options item. 0 = Beredskap, 1 = Förbundsledning.

How to set selectedIndex of select element using display text?

How to set selectedIndex of select element using display text as reference?
Example:
<input id="AnimalToFind" type="text" />
<select id="Animals">
<option value="0">Chicken</option>
<option value="1">Crocodile</option>
<option value="2">Monkey</option>
</select>
<input type="button" onclick="SelectAnimal()" />
<script type="text/javascript">
function SelectAnimal()
{
//Set selected option of Animals based on AnimalToFind value...
}
</script>
Is there any other way to do this without a loop? You know, I'm thinking of a built-in JavaScript code or something. Also, I don't use jQuery...
Try this:
function SelectAnimal() {
var sel = document.getElementById('Animals');
var val = document.getElementById('AnimalToFind').value;
for(var i = 0, j = sel.options.length; i < j; ++i) {
if(sel.options[i].innerHTML === val) {
sel.selectedIndex = i;
break;
}
}
}
<script type="text/javascript">
function SelectAnimal(){
//Set selected option of Animals based on AnimalToFind value...
var animalTofind = document.getElementById('AnimalToFind');
var selection = document.getElementById('Animals');
// select element
for(var i=0;i<selection.options.length;i++){
if (selection.options[i].innerHTML == animalTofind.value) {
selection.selectedIndex = i;
break;
}
}
}
</script>
setting the selectedIndex property of the select tag will choose the correct item. it is a good idea of instead of comparing the two values (options innerHTML && animal value) you can use the indexOf() method or regular expression to select the correct option despite casing or presense of spaces
selection.options[i].innerHTML.indexOf(animalTofind.value) != -1;
or using .match(/regular expression/)
If you want this without loops or jquery you could use the following
This is straight up JavaScript. This works for current web browsers. Given the age of the question I am not sure if this would have worked back in 2011. Please note that using css style selectors is extremely powerful and can help shorten a lot of code.
// Please note that querySelectorAll will return a match for
// for the term...if there is more than one then you will
// have to loop through the returned object
var selectAnimal = function() {
var animals = document.getElementById('animal');
if (animals) {
var x = animals.querySelectorAll('option[value="frog"]');
if (x.length === 1) {
console.log(x[0].index);
animals.selectedIndex = x[0].index;
}
}
}
<html>
<head>
<title>Test without loop or jquery</title>
</head>
<body>
<label>Animal to select
<select id='animal'>
<option value='nothing'></option>
<option value='dog'>dog</option>
<option value='cat'>cat</option>
<option value='mouse'>mouse</option>
<option value='rat'>rat</option>
<option value='frog'>frog</option>
<option value='horse'>horse</option>
</select>
</label>
<button onclick="selectAnimal()">Click to select animal</button>
</body>
</html>
document.getElementById('Animal').querySelectorAll('option[value="searchterm"]');
in the index object you can now do the following:
x[0].index
Try this:
function SelectAnimal()
{
var animals = document.getElementById('Animals');
var animalsToFind = document.getElementById('AnimalToFind');
// get the options length
var len = animals.options.length;
for(i = 0; i < len; i++)
{
// check the current option's text if it's the same with the input box
if (animals.options[i].innerHTML == animalsToFind.value)
{
animals.selectedIndex = i;
break;
}
}
}
You can set the index by this code :
sel.selectedIndex = 0;
but remember a caution in this practice, You would not be able to call the server side onclick method if you select the previous value selected in the drop down..
Add name attribute to your option:
<option value="0" name="Chicken">Chicken</option>
With that you can use the HTMLOptionsCollection.namedItem("Chicken").value to set the value of your select element.
You can use the HTMLOptionsCollection.namedItem()
That means that you have to define your select options to have a name attribute and have the value of the displayed text.
e.g
California

Search a dropdown

I have this HTML dropdown:
<form>
<input type="text" id="realtxt" onkeyup="searchSel()">
<select id="select" name="basic-combo" size="1">
<option value="2821">Something </option>
<option value="2825"> Something </option>
<option value="2842"> Something </option>
<option value="2843"> _Something </option>
<option value="15999"> _Something </option>
</select>
</form>
I need to search trough it using javascript.
This is what I have now:
function searchSel() {
var input=document.getElementById('realtxt').value.toLowerCase();
var output=document.getElementById('basic-combo').options;
for(var i=0;i<output.length;i++) {
var outputvalue = output[i].value;
var output = outputvalue.replace(/^(\s| )+|(\s| )+$/g,"");
if(output.indexOf(input)==0){
output[i].selected=true;
}
if(document.forms[0].realtxt.value==''){
output[0].selected=true;
}
}
}
The code doesn't work, and it's probably not the best.
Can anyone show me how I can search trough the dropdown items and when i hit enter find the one i want, and if i hit enter again give me the next result, using plain javascript?
Here's the fixed code. It searches for the first occurrence only:
function searchSel() {
var input = document.getElementById('realtxt').value;
var list = document.getElementById('select');
var listItems = list.options;
if(input === '')
{
listItems[0].selected = true;
return;
}
for(var i=0;i<list.length;i++) {
var val = list[i].value.toLowerCase();
if(val.indexOf(input) == 0) {
list.selectedIndex = i;
return;
}
}
}
You should not check for empty text outside the for loop.
Also, this code will do partial match i.e. if you type 'A', it will select the option 'Artikkelarkiv' option.
Right of the bat, your code won't work as you're selecting the dropdown wrong:
document.getElementById("basic-combo")
is wrong, as the id is select, while "basic-combo" is the name attribute.
And another thing to note, is that you have two variable named output. Even though they're in different scopes, it might become confusing.
For stuff like this, I'd suggest you use a JavaScript library like jQuery (http://jquery.com) to make DOM interaction easier and cross-browser compatible.
Then, you can select and traverse all the elements from your select like this:
$("#select").each(function() {
var $this = $(this); // Just a shortcut
var value = $this.val(); // The value of the option element
var content = $this.html(); // The text content of the option element
// Process as you wish
});

Categories