I have a list of dynamically generated <selects>s in a form. I need to make it so that if the user decides go back to an earlier <select>, all <select> that come after it will be removed from the page.
My code below will console.log the correct <select> elements to be removed, but if I start removing them, then it stops working. I'm looping using a non-live list, so I'm confused about why it's not working as expected.
HTML:
<form action="#" method="post">
<label for="select1">square 1:</label>
<select name="1" id="select1"></select>
<label for="select2">square 2:</label>
<select name="2" id="select2"></select>
<label for="select3">square 3:</select>
<select name="3" id="select3"></select>
...
</form>
JS (select is the currently selected <select>):
var form = document.getElementsByTagName('form')[0];
var selects = form.getElementsByTagName('select');
for (var i = 0; i < selects.length; i++) {
if (selects[i].name > select.name) {
var eleToRemove = selectsLive[selects[i].getAttribute('name') - 1];
console.log(eleToRemove);
form.removeChild(eleToRemove.previousSibling); // removes label
form.removeChild(eleToRemove);
}
}
It works when it is written correctly
var sel= 2; // for example
var form = document.getElementsByTagName('form')[0];
var selects = form.getElementsByTagName('select');
for (var i = selects.length-1; i >= 0; i--) {
if (+selects[i].name > sel) {
var eleToRemove = selects[i];
console.log(eleToRemove);
form.removeChild(eleToRemove.previousElementSibling); // removes label
form.removeChild(eleToRemove);
}
}
Related
I'm collected a variable from the user, a person name, and storing that in a variable. When I hit next, I want to display the name on several different locations, including a dropdown list. I can get it to display the name outside the dropdown list, but only once.
Here is my html:
Collecting the info
<label>Student Name</label>
<input type="text" name="Student Name" id="kidNameInput">
My Next button
<input type="button" value="Next" class="button" onclick="nextForm()"></input>
Displaying the info
<label>What did the student do well?</label>
<div class="custom-select">
<select name="did-well">
<option value="0"><span class="kid-name"></span> did a great job at…</option>
<option value="1"><span class="kid-name"></span> did this…</option>
<option value="2"><span class="kid-name"></span> did something else…</option>
<option value="3"><span class="kid-name"></span> was good…</option>
</select>
Here is my javascript:
function nextForm() {
var nameInput = document.getElementById("kidNameInput").value;
document.getElementsByClassName("kid-name")[0].innerText = nameInput;
}
I don't know if it helps. but between forms, all I am doing is hiding them. not sure if I need to have them on a seperate html pages or not.
It looks like you're only displaying the variable on index 0 (this first index).
When you perform getElementsByClassName it returns an array like object.
So in your code where you have :
document.getElementsByClassName("kid-name")[0].innerText = nameInput;
You should instead try something like:
let arr = document.getElementsByClassName("kid-name");
for(let i=o; i<arr.length; i++) {
arr[i].innerText = nameInput
}
You're getting only the fist kid-name and not all of them. You need to cycle the result of the function getElementsByClassName
function nextForm() {
var nameInput = document.getElementById("kidNameInput").value;
var x = document.getElementsByClassName("kid-name");
for (var i = 0; i < x.length; i++) {
x[i].innerText = nameInput;
}
};
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
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 a form where you select a location, this location has a zip code tied to it and is captured in the data-foo value. What I need is an array built upon multiple locations being selected.
An example would be if both would be selected I'd have 65807 => 71118
Form:
<form enctype='multipart/form-data' role='form' action='' method='post'>
<div class="row">
<div class="col-md-3">
<div class='form-group'>
<label for='select'>Destination(s) </label>
<select name='destination[]' style='height: 200px;' multiple class='form-control' multiple='multiple' id='destination' style='lane'>";
<option value='Springfield' data-foo='65807'>Springfield, MO</option>
<option value='Shreveport' data-foo='71118'>Shreveport, LA</option>
</select>
</div>
</div>
</div>
</form>
What I have so far for JS:
$(function(){
$('#origin').change(function(){
var selected = $(this).find('option:selected');
$('#origin_zip').html(selected.data('foo'));
}).change();
});
$('#destination').change(function() {
$('#destination_zip').text('');
var selected = $('#destination').val();
for (var i = 0; i < selected.data; i++) {
$('#destination_zip').data($('#destination_zip').data('data-foo') + selected[i]);
}
});
EDIT:
This is the code that works on building the array with the text, but not the data-foo that I need.
$('#destination').change(function() {
$('#destination_zip').text('');
var selected = $('#destination').val();
for (var i = 0; i < selected.length; i++) {
$('#destination_zip').text($('#destination_zip').text() + selected[i]);
}
});
The following could be used:
$('#destination').change(function() { // Whenever the select is changed
var arr = []; // Create an array
$('#destination option:selected').each(function(){ // For each selected location
arr.push($(this).data("foo")); // Push its ZIP to the array
});
console.log(arr); // will include the ZIP code(s) of selected location(s).
});
jsFiddle example here
Something like this?
(kind of ugly, I know)
$('#destination').change(function() {
var selected = [];
for(i = 0; i < $('#destination').children().length; i++){
selected[i] = $($('#destination').children()[i]).data('foo');
}
console.log(selected);
});
Edit: nevermind, look at #dsg's answer
I have 2 drop down menus which both have 'name'=list1. I also have 2 radio buttons 'yes' or 'no'. When select no all dropdown menus should be hidden, when selected 'yes' all drop down menus should show however at the minute only one is showing when clicked yes none showing when clicked no.
JavaScript code to hide:
<script type="text/javascript">
function showDiv(targetElement,toggleElementClass){
var els,
i;
if (targetElement.checked) {
els = document.getElementsByClassName(toggleElementClass);
for (i=0; i < els.length; i++) {
els[i].style.visibility = "visible";
els[i].style.display = "block";
}
}
}
function HideDiv(targetElement,toggleElementClass){
var els,
i;
if (targetElement.checked) {
els = document.getElementsByClassName(toggleElementClass);
for (i=0; i < els.length; i++) {
els[i].style.visibility = "visible";
els[i].style.display = "block";
}
// and similar for hideDiv()
</script>
code for 1st dropdwon:
<div style="display: none;" class="list1" >
<select name="colour">
<option>Please Select</option>
<option>red</option>
<option>orange</option>
<option>blue</option>
</select>
code for 2nd drop down:
<div id="list2" style="display: none;" class="list2" >
<select name="shade">
<option>Please Select</option>
<option>dark</option>
<option>light</option>
</select>
</div>
only the 1st is displaying on webpage. does anyone know why?
The id attribute is supposed to be unique, i.e., no two elements should have the same id. If you have two (or more) elements with the same id the document.getElementById() method will likely return the first - behaviour may vary from browser to browser but in any case it will definitely only return either one element or null.
If you want to apply the same change to multiple similar elements you could try giving those elements the same class and select them with the .getElementsByClassName() method:
<div class="list1"></div>
<div class="list1"></div>
<script>
function showDiv(targetElement,toggleElementClass){
var els,
i;
if (targetElement.checked) {
els = document.getElementsByClassName(toggleElementClass);
for (i=0; i < els.length; i++) {
els[i].style.visibility = "visible";
els[i].style.display = "block";
}
}
}
// and similar for hideDiv()
</script>
Another method you might like to look into is .getElementsByTagName().
Notice that .getElementById() is "element", singular, while the other two methods I mentioned get "elements", plural...
EDIT: My apologies, I don't think IE supported .getElementsByClassName() until version 9. If you are using IE8 you can substitute the following line in the above function:
els = document.querySelectorAll("div." + toggleElementClass);
and the rest should work as is. Here is a demo that I've tested as working in IE8: http://jsfiddle.net/CVS2F/1/
Alternatively for even older IE version support where you can't use .querySelectorAll() you could just use .getElementsByTagName("div") and then within the loop test each returned element to see if it has the class you care about. Here's an updated demo that works that way: http://jsfiddle.net/CVS2F/2/
To clear all your confusion, I came up with working test HTML below. Save the code as HTML and test if is it give what you wanted?
What you need to do is change 'id' to 'class', so you can select multiple elements into an array. Iterate that array and apply the style.
<html>
<head>
<script>
window.onload=registerEventHandlers;
document.getElementsByClassName = function (cn) {
var rx = new RegExp("(?:^|\\s)" + cn+ "(?:$|\\s)");
var allT = document.getElementsByTagName("*"), allCN = [], ac="", i = 0, a;
while (a = allT[i=i+1]) {
ac=a.className;
if ( ac && ac.indexOf(cn) !==-1) {
if(ac===cn){ allCN[allCN.length] = a; continue; }
rx.test(ac) ? (allCN[allCN.length] = a) : 0;
}
}
return allCN;
}
function registerEventHandlers()
{
document.getElementById("radio1").onclick = function(){
hideDiv(this,"list1")
};
document.getElementById("radio2").onclick = function(){
showDiv(this,"list1")
};
}
function showDiv(targetElement,toggleElementId){
var showAll=document.getElementsByClassName(toggleElementId);
for(i in showAll){
showAll[i].style.visibility="visible";
showAll[i].style.display="block";
}
}
function hideDiv(targetElement,toggleElementId){
var hideAll=document.getElementsByClassName(toggleElementId);
for(i in hideAll){
hideAll[i].style.visibility="hidden";
hideAll[i].style.display="none";
}
}
</script>
</head>
<body>
Yes:<input type="radio" id="radio2" name="yesNo" value="yes" />
No:<input type="radio" id="radio1" name="yesNo" value="no"/>
<div class="list1" style="display: none;" >
<select name="colour">
<option>Please Select</option>
<option>red</option>
<option>orange</option>
<option>blue</option>
</select>
</div>
<div class="list1" style="display: none;" >
<select name="shade">
<option>Please Select</option>
<option>dark</option>
<option>light</option>
</select>
</div>
</body>
</html>