I have two empty select fields, I want to iterate once over some array, create an option element in each iteration, and append it to both select fields. The problem is that only the last element gets the options, the first one remains empty:
HTML
<select class="form-control" id="typeCol">
</select>
<br>
<select class="form-control" id="diffCol">
</select>
JavaScript
let typeCol = document.getElementById('typeCol');
let diffCol = document.getElementById('diffCol');
for (let i in cols) {
let opt = document.createElement('option');
opt.value = i;
opt.innerHTML = cols[i];
typeCol.appendChild(opt);
diffCol.appendChild(opt);
}
Adding another for loop and appending to the second select from there seems to work, but still - what's going on?
An element can only be inside one parent. If you use appendChild on an element that already has a parent, it's moved from the old parent to the new one.
You can use cloneNode to create a clone of the element instead:
diffCol.appendChild(opt.cloneNode(true));
Example:
let typeCol = document.getElementById('typeCol');
let diffCol = document.getElementById('diffCol');
let cols = ["one", "two", "three"];
for (let i in cols) {
let opt = document.createElement('option');
opt.value = i;
opt.innerHTML = cols[i];
typeCol.appendChild(opt);
diffCol.appendChild(opt.cloneNode(true));
}
<select class="form-control" id="typeCol">
</select>
<br>
<select class="form-control" id="diffCol">
</select>
You can't append same element, However you can use cloneNode() method to create a clone then append it.
typeCol.appendChild(opt);
diffCol.appendChild(opt.cloneNode(true));
//For this you can use template tag of HTML 5 :-
<select class="form-control" id="typeCol">
<template id="typeColTemplate">
<option id="" value=""></option>
</template>
</select>
<br>
<select class="form-control" id="diffCol">
<template id="diffColTemplate">
<option id="" value=""></option>
</template>
</select>
//In JS:-
for (let i in cols){
var count =1;
var content = document.querySelector("#typeColTemplate").content;
var content = document.querySelector("#typeDiffTemplate").content;
var option = content.querySelector("option[id]");
option.id="opID" + count;
option.value=i;
option.innerHTML=i;
document.querySelector('#typeCol').appendChild(document.importNode(content, true));
document.querySelector('#diffCol').appendChild(document.importNode(content, true));
count++;
}
Related
I'd like to add the same options elements to more than one select, using one JavaScript function.
<select id="select1" name="select1"></select>
<select id="select2" name="select2"></select>
I want selects become:
<select id="select1" name="select1">
<option value="0">Txt1</option>
<option value="1">Txt2</option>
<option value="2">Txt3</option>
</select>
<select id="select2" name="select2">
<option value="0">Txt1</option>
<option value="1">Txt2</option>
<option value="2">Txt3</option>
</select>
Here is part of function to fill selects with options:
function window_onload(){
var SpecTxt = new Array("Txt1","Txt2","Txt3");
for(var i=0; i<SpecTxt.length; i++) {
var oOption = document.createElement("OPTION");
oOption.text = SpecTxt[i];
oOption.value=i;
select1.add(oOption); // Option to first SELECT
select2.add(oOption); // Option to second SELECT
}
}
But I've got Internet Explorer Script Error "Invalid argument", result is only one first option in "select1" and no options in "select2". If I remove from function window_onload() the last string select2.add(oOption);, there are no IE errors and "select1" is filled as must be, but "select2" is empty. How is it possible in JS to add the same options to different SELECTs?
Update
The reason why the Demo didn't work for IE is because it doesn't recognize the property .valueAsNumber.
From:
var opts = qty.valueAsNumber;
To:
var opts = parseInt(qty.value, 10);
When you create an option within the loop:
var oOption = document.createElement("OPTION");
That is only one <option> not two <option>s. So that is the reason why:
select1.add(oOption); // Succeeds
select2.add(oOption); // Fails
You can either make 2 <option>s per loop:
var oOption1 = document.createElement("OPTION");
var oOption2 = document.createElement("OPTION");
OR try cloneNode(). See Demo below:
Demo
// See HTMLFormControlsCollection
var form = document.forms.ui;
var ui = form.elements;
var qty = ui.qty0;
var s0 = ui.sel0;
var s1 = ui.sel1;
// Declare a counter variable outside of loop
var cnt = 0;
// Add event handler to the change event of the input
qty.onchange = addOpt;
/* Get the value of user input as a number
|| within the for loop...
|| create an <option> tag...
|| add text to it with an incremented offset...
|| add a incremented value to it...
|| then clone it...
|| add original <option> to the first <select>...
|| add duplicate <option> to the second <select>
*/
function addOpt(e) {
var opts = parseInt(qty.value, 10);
for (let i = 0; i < opts; i++) {
var opt = document.createElement('option');
opt.text = 'Txt' + (cnt + 1);
opt.value = cnt;
var dupe = opt.cloneNode(true);
s0.add(opt);
s1.add(dupe);
cnt++;
}
}
input,
select,
option {
font: inherit
}
input {
width: 4ch;
}
<form id='ui'>
<fieldset>
<legend>Enter a number in the first form field</legend>
<input id='qty0' name='qty0' type='number' min='0' max='30'>
<select id="sel0" name="sel0"></select>
<select id="sel1" name="sel1"></select>
</fieldset>
</form>
Reference
HTMLFormControlsCollection
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>
I use querySelectorAll to select 2 select elements. I then append a newly created <option> element to the two <select> elements.
However, for some reason only the last element has the option appended, the first one is ignored for some reason.
Here is my code:
displayLoading() {
let dropdowns = document.querySelectorAll('[data-search-select]');
let loadingOption = document.createElement('option');
loadingOption.innerHTML = 'Loading...';
for(let i = 0; i < dropdowns.length; i++) {
dropdowns[i].disabled = true;
dropdowns[i].innerHTML = '';
dropdowns[i].appendChild(loadingOption);
}
}
This is the HTML:
<div class="formgroup">
<label class="dropdown-search__label">Choose a make:</label>
<select name="dropdown-search__select--make" id="dropdown-search__select--make" data-search-select="make">
</select>
</div>
<div class="formgroup last">
<label class="dropdown-search__label">Choose a model:</label>
<select name="dropdown-search__select--model" id="dropdown-search__select--model" data-search-select="model">
</select>
</div>
You are creating one option element and trying to add it to two different selects. The second time you try to append the element, you grab the only option you have, remove from the current select and place into the new one. You should create two option elements, maybe moving that line into the for loop
Hope this helps :)
Node.appendChild() is not creating a copy.It is moving the existing node .so in your for loop it add option to the first select then moves it to the second and so on .So instead of that create two option elements and append to each select :
displayLoading();
function displayLoading() {
let dropdowns = document.querySelectorAll('[data-search-select]');
for(let i = 0; i < dropdowns.length; i++) {
let loadingOption = document.createElement('option');
loadingOption.innerHTML = 'Loading...';
dropdowns[i].disabled = true;
dropdowns[i].innerHTML = '';
dropdowns[i].appendChild(loadingOption);
}
}
<div class="formgroup">
<label class="dropdown-search__label">Choose a make:</label>
<select name="dropdown-search__select--make" id="dropdown-search__select--make" data-search-select="make">
</select>
</div>
<div class="formgroup last">
<label class="dropdown-search__label">Choose a model:</label>
<select name="dropdown-search__select--model" id="dropdown-search__select--model" data-search-select="model">
</select>
</div>
I have this short code which works with form tags.
<select id="district" name="lan" class="country_search"
onchange="showSubcomune(this.value,this.form.undercomune)">
<option value="0" selected>choose country </option>
<option value="10">some comue</option>
</select>
<select name="undercomune" id="undercomune" class="country_search">
<option value="0" selected >chhose comune</option>
</select>
this showSubcomune works fine with form tags when i use this.form.undercomune so it collecte comunes to selected country and show them in the undercomune select option.
the problem is i want use same function in other place BUT without html form tag. How can this be this.form.undercomune ?? in the function ?
have tried those :
this.form.undercomune
this.undercomune
$('#undercomune').val()
But no one works .
any help would be much apreciated thanks.
EDIT:
function showSubKommun(subCat,selectObj) {
selectObj.length = 0;
var j = 0,
elm;
for (var k = 0; (elm = kommun[k]); ++k)
if (elm.lankod == subCat)
selectObj[j++] = new Option(elm.namn, elm.kommunkod);
var x = document.getElementById("undercomune");
var option = document.createElement("option");
option.text = " \xAB choose comune \u00bb ";
option.value = 0;
x.add(option,x[0]);
x[0].setAttribute("selected", "selected");
}
You can get it either by document.getElementById
var elem = document.getElementById('undercomune');
or if you're using jQuery
elem = $('#undercomune')[0]; // the indexer returns native html element
I have a table row which looks like
the HTML looks like
When the user changes the value of the Name field I pass the "select" to nameDropChanged function. After obtaining a reference to select I want to change the value of Number of Coupons select box. How can I obtain a reference to it using Jquery? Also there will be many such exact rows in the table.
Update : Here is the dummy HTML code and jsfiddle link
<table id="competitors_table" width="100%" style="border-bottom: #000000 solid 1px;">
<tbody>
<tr>
<td>Name:<select name="CompetitorIDs_Setting_[]" onchange="nameDropDownChanged(this);">
<option value="0">N/A</option><optgroup label="Similar Stores"></optgroup>
<optgroup label="Other Stores">
<option value="1">flipkart</option>
<option value="2">bigshoebazaar</option>
<option value="160">presto</option>
<option value="3">fabindia</option>
<option value="4">fashnvia</option>
</td>
<td>
<select name="Position_Setting_[]" onchange="dropDownChanged(this);">
<option value="1000">Top</option>
<option value="1001">Middle</option>
<option value="1002">Bottom</option>
<option value="">Enter Position</option>
</select>
<input type="text" name="PositionNumber_Setting_[]" size="3" style="display: none;">
</td>
<td>Number of Coupons:<select id="numberOfCoupons_Setting_[]"></select></td>
</tr>
</tbody>
</table>
Javascript code
function nameDropDownChanged(select)
{
var selectedIndex = select.selectedIndex;
var WebsiteName = select.options[selectedIndex].innerHTML;
var couponCount = <?php if(!empty($couponCount)){ echo json_encode($couponCount); }?>;
if(Object.keys(couponCount).length > 0)
{
var numberOfCoupons = couponCount[WebsiteName];
var numberOfCouponsDropDown = document.getElementById('numberOfCouponsSelect');
$("#numberOfCouponsSelect").empty();
if(numberOfCoupons > 0)
{
for(var i=1; i <= numberOfCoupons; i++)
{
var option = document.createElement('option');
option.value = i;
option.innerHTML = i;
numberOfCouponsDropDown.appendChild(option);
}
}
else
{
var option = document.createElement('option');
option.value=1;
option.innerHTML = "No Active Coupons";
numberOfCouponsDropDown.appendChild(option);
}
}
}
inside the nameDropChanged function ..
// considering 'parameter' is the variable to be passed as a parameter to nameDropChanged function
$numberSelect = $(parameter).parent().nextAll(':last').children('select');
// $numberSelect is now containing a reference to the numberOfCoupons_Setting_[ select]
You can do something like this
$('#Selector_ID1, #Selector_ID2, #Selector_ID3, ...').change(function() {
var parent = $(this).parents("tr");
var elm = $("td:last-child", parent).children("select");
//Do your operation with last Select Element here.
});
This helps in two ways
You need not to know exact parents and children, but just reverse
track for parent which is TR in first case and then last SELECT in
the parent.
In a single go you can handle multiple rows. You can
also use class selector here.