Appending <option> only appending to last element in list - javascript

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>

Related

How to generate multiple <select> elements with option tags?

I'm trying to append the defined select element to the document.
This answer, describes quite well about fixed arrays, but in my case I have a slice which is applied to the template by ExecuteTemplate method, so the value of <option> tags are defined by slice values.
Here is my code which does not work, as it should:
<html>
<input type="number" id="count">
<select id="select">
{{ range .Slice }}
<option value="{{ .Name }}">{{ .Name }}</option>
{{ end }}
</select>
<div class="test"></div>
<button onclick="generateSelects();">Test</button>
</html>
<script>
function generateSelects() {
var count = document.getElementById("count").value;
var i;
var select = document.getElementById("select");
var divClass = document.getElementsByClassName("test");
for (i = 0; i < Number(count); i++) {
divclass[0].appendChild(select);
)
}
</script>
What am I looking for is about generating select list based on the user's input. For example if the user enters 2, so two select menu going to appear on the screen.
How can I do this?
First of all make sure that generated selects all have different IDs, in your example they all have the same id which is "select".
Then instead of appending the "original" select element, try to clone it then add its clone to your div.
What I would do is :
function generateSelects() {
var count = document.getElementById("count").value;
var i;
var select = document.getElementById("select");
var divClass = document.getElementsByClassName("test");
for (i = 0; i < Number(count); i++) {
var clone = select.cloneNode(true); // true means clone all childNodes and all event handlers
clone.id = "some_id";
divclass[0].appendChild(clone);
}
}
Hope it helps!
To append multiple select elements, first you have create a select element. You can not directly get an elementById and append different element as child.
<script>
function generateSelects() {
var count = document.getElementById("count").value;
var i;
var divClass = document.getElementsByClassName("test");
for (i = 0; i < Number(count); i++) {
var option = document.createElement("OPTION");
option.setAttribute("value", "optionvalue");
var select = document.createElement("SELECT");
select.appendChild(option);
divclass[0].appendChild(select);
)
}
</script>

Remove all <select> elements after the one that has been selected

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);
}
}

Appending the same element to different elements

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++;
}

Iterating through elements returned by jQuery selector

I have some HTML that's structured more or less like which I want to be able to filter though by row.
<div class="parentElement">
<div class="rowInput">
<input type="checkbox" />
<input type="text" value="demo" />
</div>
<div class="rowInput">
<input type="checkbox" />
<input type="text" value="demo" />
<select>
<option>Value 1</option>
<option>Value 2</option>
</select>
</div>
</div>
I'm able to get the two rows I need with
var row = $('.rowInput');
0: div.row.inputRow
1: div.row.inputRow
However I'm having issues with going through these rows and further and pulling out any information. I've tried a few different methods of looping through the rows however the best I've been able to do is traversing the property list of the elements. What want to do however is go through each element of the div.row.inputRow and pull out the information based on element type so I can store the information by row.
Edit: I was able to get what I wanted with the following code:
for (var i = 0; i < rows.length; i++) {
console.log(rows[i]);
for (var j = 0; j < rows[i].childNodes.length; j++) {
console.log(rows[i].childNodes[j]);
}
}
However I'm getting errors whenever I try to use the jQuery '.is()' on the child nodes I'm returning
Uncaught TypeError: rows[i].childNodes[j].is is not a function
Basically what I'm going for in the end is returning each element with '.inputRow' so I can filter out the input of each row and either store it or discard it based on if the checkbox is selected. The main reason I'm going this route is I couldn't get the input I needed by row with both a 'select' and ':input' selector.
Your code is correct except for the way to get childerens try the following:
var rows = $('.rowInput');
for (var i = 0; i < rows.length; i++) {
console.log(rows[i]);
for (var j = 0; j < $(rows[i]).children().length; j++) {
console.log( $(rows[i]).children()[j]);
}
}
check it here: jsfiddle
Try each() function:
$('.rowInput').each(function() {
var $this = $(this);
var checkbox = $this.find('input[type=checkbox]');
var text = $this.find('input[type=text]');
});
The $(this) refers to each .rowInput element.

dropdown menu not showing?

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>

Categories