querySelectorAll loop "undefined" - javascript

I try to loop over few input elements in order to get each value, but for some reason I only get the last one:
<input type="text" name="input-loop" data-loop="true" />
<input type="text" name="input-loop" data-loop="true" />
<input type="text" name="input-loop" data-loop="true" />
<button type="button" onclick="loop()">loop</button>
<div id="output"></div>
<script>
function loop() {
var element = document.querySelectorAll('[data-loop="true"]');
for(var i = 0; i < element.length; i++) {
console.log(element[i].length);
// or:
// document.getElementById('output').innerHTML = element[i].value + '<br>';
}
}
</script>
The console shows undefined and when I try to output the values, I only get it from the last element and not from all of them. What am I doing wrong?
Thank you very much (and please excuse my english)

You are trying to get the length of the element itself:
console.log(element[i].length);
Elements don't have a length.
I suspect you are trying to get the length of the value of the elements:
console.log(element[i].value.length);
function loop() {
// elements will be a "node list" containing any/all elements
// that match the query.
var elements = document.querySelectorAll('[data-loop="true"]');
// Because it is a node list, which is an array-like object,
// it has a "length" property:
console.log("There were " + elements.length + " elements found.");
// ...And, it can be looped through
for(var i = 0; i < elements.length; i++) {
// It's contained elements are indexed and when you do that,
// you may access properties of the elements themselves
console.log(elements[i].value);
// or:
document.getElementById('output').innerHTML += elements[i].value + '<br>';
}
}
<p>Type some text in the textboxes and then click the button:</p>
<input type="text" name="input-loop" data-loop="true" />
<input type="text" name="input-loop" data-loop="true" />
<input type="text" name="input-loop" data-loop="true" />
<button type="button" onclick="loop()">loop</button>
<div id="output"></div>

try to console.log(element[i]); This is because here element will be a collection of DOM elements.
There is no length property for these elements.
Since they are input and if you want to get their value you need to log
element[i].value

What am I doing wrong?
console.log(element[i].length);
element[i] refers to an HTMLInputElement. It and non of its parent classes have a length property. Assuming you want to display the length of the value of the input element, the following would work.
var output = document.getElementById('output');
function loop() {
var element = document.querySelectorAll('[data-loop="true"]');
element.forEach( (e) => {
output.innerHTML += `${e.value}: ${e.value.length}<br>`;
});
}
function clearOutput(){
output.innerHTML = '';
}
<input type="text" name="input-loop" data-loop="true" value="one" />
<input type="text" name="input-loop" data-loop="true" value="two" />
<input type="text" name="input-loop" data-loop="true" value="three" />
<button type="button" onclick="loop()">loop</button>
<button type="button" onclick="clearOutput()">clear</button>
<div id="output"></div>

Related

How to grab values of checkboxes in an array

I have a div as follows:
<div class="questionholder" id="question5" style="display:none">
<div>
<h5>Select all that apply</h5>
<input class="input5" type="checkbox" id="ID1elementColor" name="ID1element" value="color"><label for="ID1elementColor"><p class="radioChoice">Color</p></label>
<input class="input5" type="checkbox" id="ID1elementHeight" name="ID1element" value="height"><label for="ID1elementHeight"><p class="radioChoice">Height</p></label>
<input class="input5" type="checkbox" id="ID1elementWeight" name="ID1element" value="weight"><label for="ID1elementWeight"><p class="radioChoice">Weight</p></label>
</div>
</div>
<div class="holdButtons">
<a class="text2button" onclick="displayquestion(6);">Next</a>
</div>
The user is expected to select all the checkboxes that apply to his situation. Let's assume he selects all 3.
When he clicks "Next", the function displayquestion(); will fire.
function displayquestion(a) {
var Elements = '';
var b = a - 1;
Elements = document.querySelector("#question" + b + " input[name=ID1element]").value;
}
Basically, the function is meant to store all the checked values into var Elements, which is meant to be an array.
However, I'm only getting the value of the first selected answer instead of an array of all selected answers.
How do I grab all the selected answers into an array?
No jQuery please.
Use querySelectorAll to get an array-like NodeList instead of querySelector, and then you can use Array.from to transform that NodeList into an array containing only the .value of the selected inputs:
function displayquestion(a) {
const b = a - 1;
const elements = Array.from(
document.querySelectorAll('#question' + b + ' input:checked'),
input => input.value
);
console.log(elements);
}
<div class="questionholder" id="question5">
<div>
<h5>Select all that apply</h5>
<input class="input5" type="checkbox" id="ID1elementColor" name="ID1element" value="color"><label for="ID1elementColor"><p class="radioChoice">Color</p></label>
<input class="input5" type="checkbox" id="ID1elementHeight" name="ID1element" value="height"><label for="ID1elementHeight"><p class="radioChoice">Height</p></label>
<input class="input5" type="checkbox" id="ID1elementWeight" name="ID1element" value="weight"><label for="ID1elementWeight"><p class="radioChoice">Weight</p></label>
</div>
</div>
<div class="holdButtons">
<a class="text2button" onclick="displayquestion(6);">Next</a>
</div>
Here is the script that you can use for that:
I haven't changed anything in your HTML structure. Except I have removed the display: none; from the style attribute of the class questionholder.
<script>
function displayquestion(b) {
let checkboxList = document.querySelectorAll("#question" + b + " input:checked");
let obj = [];
if (checkboxList.length > 0) { //Code works only if some checbox is checked
checkboxList.forEach(function(item) {
obj.push(item.value); //Contains the value of all the selected checkboxes.
});
}
console.log(obj); //array list containing all the selected values
}
</script>
<div class="questionholder" id="question5" style="">
<div>
<h5>Select all that apply</h5>
<input class="input5" type="checkbox" id="ID1elementColor" name="ID1element" value="color"><label for="ID1elementColor"><p class="radioChoice">Color</p></label>
<input class="input5" type="checkbox" id="ID1elementHeight" name="ID1element" value="height"><label for="ID1elementHeight"><p class="radioChoice">Height</p></label>
<input class="input5" type="checkbox" id="ID1elementWeight" name="ID1element" value="weight"><label for="ID1elementWeight"><p class="radioChoice">Weight</p></label>
</div>
</div>
<div class="holdButtons">
<a class="text2button" onclick="displayquestion(5);">Next</a>
</div>
Here is a JSFiddle link for that.
I hope this is helpful.
So first of I would make a variable for your
<a class="text2button">Next</a>. And I have removed the
onclick="displayquestion(6)" from your html.
Here is the variable.
var text2button = document.getElementsByClassName("text2button")[0];
text2button.addEventListener("click", displayquestion);
Here we have the function, so what I've done is.
I have created a variable var elements = []; Which is a empty array.
Then I create this variable var inputs = document.getElementsByClassName("input5");
This variable gets all the inputs with class input5.
Next I would loop through each of the inputs from the var inputs. Like this.
for (var i = 0; i < inputs.length; i++) {
if (inputs[i].checked) {
elements.push(inputs[i].value);
}
}
So what I do here is loop through each input for (var i = 0; i < inputs.length; i++) and then I check if any of the inputs are checked if (inputs[i].checked), then I push them to the array var elements with elements.push(inputs[i].value);.
And then I use console.log(elements); so show it in the console.
Check out the snippet below to see it in effect.
Hope this helps.
var text2button = document.getElementsByClassName("text2button")[0];
text2button.addEventListener("click", displayquestion);
function displayquestion() {
var elements = [];
var inputs = document.getElementsByClassName("input5");
for (var i = 0; i < inputs.length; i++) {
if (inputs[i].checked) {
elements.push(inputs[i].value);
}
}
console.log(elements);
}
<div class="questionholder" id="question5">
<div>
<h5>Select all that apply</h5>
<input class="input5" type="checkbox" id="ID1elementColor" name="ID1element" value="color"><label for="ID1elementColor"><p class="radioChoice">Color</p></label>
<input class="input5" type="checkbox" id="ID1elementHeight" name="ID1element" value="height"><label for="ID1elementHeight"><p class="radioChoice">Height</p></label>
<input class="input5" type="checkbox" id="ID1elementWeight" name="ID1element" value="weight"><label for="ID1elementWeight"><p class="radioChoice">Weight</p></label>
</div>
</div>
<div class="holdButtons">
<a class="text2button">Next</a>
</div>

Trying to validate values inside a loop

Trying to validate a multi-form data. If class "a" is checked it has to check whether class "b" is empty or not.
c = 1;
d = 1;
$('.a').each(function() {
if ($(this).is(':checked')) {
$('.b').each(function() {
if ($(this).val() == '') {
err += "<p>Value Empty at row +c+</p>";
return false;
}
d = d + 1;
});
}
c = c + 1;
});
<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js"></script>
<label><input type="checkbox" class="a" name="a[]" value="Value" /> Value</label><br> <input type="text" class="b" name="b[]" />
The Issue is, it validates perfectly for the first form. when it comes to second form, it checks the first value of class 'b' instead of checking second value of class 'b'
You don't want the .b loop inside the .a loop. You want a single loop handling both:
var checkboxes = $(".a");
var textboxes = $(".b");
for (var n = 0; n < checkboxes.length; ++n) {
if (checkboxes[n].checked && !textboxes[n].value.trim()) {
err += "<p>Value Empty at row " + n + "</p>";
}
}
Live Example:
$("#btn").on("click", function() {
var err = "";
var checkboxes = $(".a");
var textboxes = $(".b");
for (var n = 0; n < checkboxes.length; ++n) {
if (checkboxes[n].checked && !textboxes[n].value.trim()) {
err += "<p>Value Empty at row " + n + "</p>";
}
}
$("#err").html(err);
});
<label><input type="checkbox" class="a" name="a[]" value="Value" /> Value</label><br> <input type="text" class="b" name="b[]" />
<br>
<label><input type="checkbox" class="a" name="a[]" value="Value" /> Value</label><br> <input type="text" class="b" name="b[]" />
<br>
<label><input type="checkbox" class="a" name="a[]" value="Value" /> Value</label><br> <input type="text" class="b" name="b[]" />
<br>
<input type="button" id="btn" value="Check">
<div id="err"></div>
<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js"></script>
A couple of notes:
When you use [n] to index into a jQuery object, you get the raw DOM element at that position. When you have the raw element, there's no need for .is(":checked"), just use the checked property on the element itself. (So: checkboxes[n].checked instead of $(checkboxes[n]).is(":checked") or checkboxes.eq(n).is(":checked").)
Similarly, input elements have their own value property, no need to wrap them in an jQuery object just to call val().
My code above assumes that an input containing only whitespace should be considered empty. It does that with String#trim, which was introduced in ES5 (2009). If you need to support seriously obsolete browsers like IE8, you may need a polyfill for it.
When you use the code
$(".b")...
it checks all inputs with class b, but you only want the related one. The key is determining how they are related. It could be they are in a parent div or they could be matched using data- attributes, or could simply be the "next" input.
Your example HTML only shows one 'pair' of .a and .b, so if we expand that pair to multiple pairs, eg grouped in a 'group' div, you can then use .closest(".group") to find the containing div and then the related .b within that div:
$("#validate").click(function() {
var c = 1;
var d = 1;
var err = "";
$('.a').each(function() {
if ($(this).is(':checked')) {
// only find the related `.b`
//$('.b').each(function() {
$(this).closest(".group").find(".b").each(function() {
if ($(this).val() == '') {
err += "<p>Value Empty at row " + c + "</p>";
return false;
}
d = d + 1;
});
}
c = c + 1;
});
console.log("c:", c, "d:", d, err);
});
<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js"></script>
<div class='group'>
<label>
<input type="checkbox" class="a" name="a[]" value="Value" />
Value
</label>
<br>
<input type="text" class="b" name="b[]" />
</div>
<div class='group'>
<label>
<input type="checkbox" class="a" name="a[]" value="Value" />
Value
</label>
<br>
<input type="text" class="b" name="b[]" />
</div>
<button id='validate' type='button'>validate</button>
When you're doing $('.b').each(function(){}) it's finding all the elements with class .b again/each time. Hence checking for first element again.
One solution would be to first find all the elements and then run the loop and use index to find the elements
as = $(".a");
bs = $(".b");
for(var i = 0; i < as.length; i++){
a = as[i];
b = bs[i];
if($(a).is(':checked')){
if($(b).val() === ''){
err += "<p>Value Empty at row +c+</p>";
return false;
}
}
}
Or structure your markup a in such a way where all the related elements with class a & b are put inside a div.
You can find all the .a and while looping you'll find all the .b inside the parent div
<div class='wrapper-related-fields'>
<label><input type="checkbox" class="a" name="a[]" value="Value" /> Value</label>
<br>
<input type="text" class="b" name="b[]" />
</div>
$('.a').each(function(){
if($(this).is(':checked')){
// Find the parent wrapper
wrapper = $(this).closest(".wrapper-related-fields");
// find all the .b elements inside wrapper
$(warpper).find('.b').each(function(){
if($(this).val() == '')
{
err += "<p>Value Empty at row +c+</p>";
return false;
}
d = d + 1;
});
}
c = c + 1;
});

Creating input element continuing ID enumeration

I have a button that creates 4 input elements inside a DIV after click:
<div id="content"></div>
<button class="check">Check</button>
<script src="https://ajax.googleapis.com/ajax/libs/jquery/1.9.1/jquery.min.js"></script>
<script>
var num = 4;
$(".check").click(function(){
for(i=0; i<num;i++){
$("#content").append("<input id='input"+i+"' type='text'><br>");
}
});
</script>
But the problem is I want input id number continues the enumeration (like this example) instead of return to zero:
<div id="content">
<input id="input0" type="text">
<input id="input1" type="text">
<input id="input2" type="text">
<input id="input3" type="text">
<input id="input4" type="text">
<input id="input5" type="text">
<input id="input6" type="text">
<input id="input7" type="text">
...and continues
</div>
How can I fix it?
You can check the id of the last input. Here I am calculating start and end of for loop based on the total number of elements in #container.
var num = 4;
$(".check").click(function() {
var start = $("#content input").length;
var end = start + num;
for (i = start; i < end; i++) {
var id = 'input' + i;
$("#content").append("<input id='"+id+"' type='text' value='"+id+"'><br>");
}
});
<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js"></script>
<div id="content"></div>
<button class="check">Check</button>
PS: Here input value is just to demonstrate the id setting to input.
You need some kind of global variable here, or use that simple one:
var getID = (function () {
var id = 0;
return function () { return ++id; }
})();
So whenever you call getID() the »internal« id will be incremented, so each call will yield an new ID.
$(".check").click(function() {
for(var i = 0; i < 4; i++) {
$('<input type="text">') //create a new input
.attr('id', 'input' + $('#content input').length) //id based on number of inputs
.appendTo('#content'); //append it to the container
}
});
<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js"></script>
<div id="content"></div>
<button class="check">Check</button>
If you're asking how to have a stack of elements to begin with, and then continue enumeration from there, you simply need to set a variable to the ID of the latest element.
All you need to do is count the number of elements. This can be done with a combination of .querySelectorAll() and .length.
Then simply have your loop start at this new value instead of 0.
This can be seen in the following:
var total_desired = 20;
var start = document.querySelectorAll('#content > input').length;
console.log(start + " elements to start with");
$(".check").click(function() {
for (i = start; i < total_desired; i++) {
$("#content").append("<input id='input" + i + "' type='text'><br>");
}
});
<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js"></script>
<button class="check">Check</button>
<div id="content">
<input id="input0" type="text">
<input id="input1" type="text">
<input id="input2" type="text">
<input id="input3" type="text">
<input id="input4" type="text">
<input id="input5" type="text">
<input id="input6" type="text">
<input id="input7" type="text"> ...and continues
</div>
Having said that, it's unlikely that you actually need simultaneous ID <input> elements, and you may benefit from classes instead.
You can create this object:
var MyId = {
a: 0,
toString() {
return this.a++;
}
}
And concatenate it into the string. Automatically will increase the counter.
<div id="content"></div>
<button class="check">Check</button>
<script src="https://ajax.googleapis.com/ajax/libs/jquery/1.9.1/jquery.min.js"></script>
<script>
var GetID = {
a: 0,
toString() {
return this.a++;
}
}
var num = 4;
$(".check").click(function(){
for(i=0; i<num;i++){
$("#content").append("<input id='input"+GetID+"' type='text'><br>");
}
});
</script>

get required form elements via DOM in javascript

To do checking on required fields and a custom method of alerting users that required fields are missing, I'm trying to get an array of elements in a form, and have been hunting but not finding a good method.
Is there some variation of
document.getElementById(form).elements;
that would return all the required elements of an array, or a way to test if a given element is required... something akin to either
var my_elements = document.getElementById(form).required_elements;
or
var my_elements = document.getElementById(form).elements;
for (var this_element in my_elements){
if (this_element.attributes["required"] == "false"){
my_elements.splice(this_element, 1);
}
}
Try querySelectorAll with an attribute selector:
document.getElementById(form).querySelectorAll("[required]")
var requiredElements = document.getElementById("form").querySelectorAll("[required]"),
c = document.getElementById("check"),
o = document.getElementById("output");
c.addEventListener("click", function() {
var s = "";
for (var i = 0; i < requiredElements.length; i++) {
var e = requiredElements[i];
s += e.id + ": " + (e.value.length ? "Filled" : "Not Filled") + "<br>";
}
o.innerHTML = s;
});
[required] {
outline: 1px solid red;
}
<form id="form">
<input required type="text" id="text1" />
<input required type="text" id="text2" />
<input type="text" id="text3" />
<input type="text" id="text4" />
<input required type="text" id="text5" />
</form>
<br>
<button id="check">Check</button>
<br>
<div id="output">
Required inputs
</div>

jQuery add ID increment to .html() appending on input onchange and refresh onchange value

I apologize for the wordy title but I haven't found a solution to my problem yet. I am a newbie with jQuery and web development so any guidance would be appreciated.
I have a <input> that allows user to enter a value (number) of how many rows of a set of input fields they want populated. Here's my example:
<div id="form">
<input id="num" name="num" type="text" />
</div>
<p> </p>
<div id="form2">
<form action="" method="post" class="form_main">
<div class="data">
<div class="item">
<input id="name" name="name[]" type="text" placeholder="name" /><br/>
<input id="age" name="age[]" type="text" placeholder="age" /><br/>
<input id="city" name="city[]" type="text" placeholder="city" /><br/>
<hr />
</div>
</div>
<button type="submit" name="submit">Submit</button>
</form>
My jQuery:
<script>
var itemNum = 1;
$("#num").on("change", function() {
var count = this.value;
var item = $(".item").parent().html();
//item.attr('id', 'item' + itemNum);
for(var i = 2; i <= count; i++) {
itemNum++;
$(".data").append(item);
}
})
</script>
I'm having problems adding an ID item+itemNum increment to <div class="item">... item.attr() didn't work. It doesn't append once I added that line of code.
Also, how can I get it so that once a user enters a number that populates rows of input fields, that if they change that number it will populate that exact number instead of adding to the already populated rows? Sorry if this doesn't make any sense. Please help!
Here is a DEMO
var itemNum = 1;
$("#num").on("change", function() {
$('.data div').slice(1).remove(); //code for removing previously populated elements.
var count = this.value;
console.log(count);
var item;
//item.attr('id', 'item' + itemNum);
var i;
for(i = 1; i <= count; i++) {
console.log(i);
item = $("#item0").clone().attr('id','item'+itemNum);
//prevent duplicated ID's
item.children('input[name="name[]"]').attr('id','name'+itemNum);
item.children('input[name="age[]"]').attr('id','age'+itemNum);
item.children('input[name="city[]"]').attr('id','city'+itemNum);
itemNum++;
$(".data").append(item);
}
})
Use clone() instead of html()
Try
var itemNum = 1,
item = $(".data .item").parent().html();;
$("#num").on("change", function () {
var count = +this.value;
if (itemNum < count) {
while (itemNum < count) {
itemNum++;
$(item).attr('id', 'item' + itemNum).appendTo('.data')
}
} else {
itemNum = count < 1 ? 1 : count;
$('.data .item').slice(itemNum).remove();
}
})
Demo: Fiddle

Categories