Creating Forms in Javascript-Length is undefined - javascript

So I feel silly asking this question, but am currently a high school student in Coding that needs help. We're working on a project with the same requirements for all people, so I took some code that worked for my friend to use for a form; however, I keep running in the problem that my 'length is undefined' and therefore, will not do what I want it to. My code is below:
HTML:
What toppings do you like on your ice-cream?
<div class="checkbox">
<label>
<input name="food" type="checkbox" value="Whip Cream">Whip Cream
</label>
</div>
<div class="checkbox">
<label>
<input name="food" type="checkbox" value="Sprinkles">Sprinkles
</label>
</div>
<div class="checkbox">
<label>
<input name="food" type="checkbox" value="Fruit">Fruit
</label>
</div>
<div class="checkbox">
<label>
<input name="food" type="checkbox" value="Hot Fudge/Caramel">Hot Fudge/Caramel
</label>
</div>
<div class="checkbox">
<label>
<input name="food" type="checkbox" value="Other">Other
</label>
</div>
<input name="Submit" type="Submit" value="Submit">
<div id="r">
</div>
Script:
var form = document.forms.example;
//This points to the form called "example" in HTML
form.addEventListener("submit",nameDisplay,false);
function nameDisplay(event) {
event.preventDefault();
var person = {
name: form.username.value,
}
var text = "<p> Mmmm..." + person.name +" sounds yummy!</p>";
document.getElementById("result").innerHTML = text;
}
var l = [];
for(i = 0; i < form.food.length; i++) {
if(form.food[i].checked) {
l.push(form.food[i].value);
}
console.log("loop");
}
console.log(l);
person.food = l;
console.log(person.food);
var text = "<p>You like" + person.food.join(",") + "on your ice-cream.</p>";
document.getElementById("r").innerHTML = text;
NOTE: I have two forms, hence the first part of javascript, but I thought maybe the problem lies within one thing is overriding another and what not or I'm missing something. I am only having problems with the ice-cream one though. Please help! Thanks in advance!

Below is the working version of your code
Issues found:
form tag was missing
There was no username input yet person needed it
The code you added
after your friend's was outside the nameDisplay function
There was no "result" div
Other concerns you may want to review
Is there a need to wrap your input's in divs?
No need for the food variable
I'd love to see the loop replaced with a filter and some
Bro, are you sure im not doing your homework?
var form = document.forms.example; //This points to the form called "example" in HTML
form.addEventListener("submit", nameDisplay, false);
function nameDisplay(event) {
var food = [];
for (i = 0; i < form.food.length; i++) {
if (form.food[i].checked) {
food.push(form.food[i].value);
}
}
var text = "<p>You like " + food.join(",") + " on your ice-cream.</p>";
document.getElementById("r").innerHTML = text;
}
<h3>What would you like on your Ice Cream?</h3>
<form id="example">
<div class="checkbox">
<label>
<input name="food" type="checkbox" value="Whip Cream">Whip Cream
</label>
</div>
<div class="checkbox">
<label>
<input name="food" type="checkbox" value="Sprinkles">Sprinkles
</label>
</div>
<div class="checkbox">
<label>
<input name="food" type="checkbox" value="Fruit">Fruit
</label>
</div>
<div class="checkbox">
<label>
<input name="food" type="checkbox" value="Hot Fudge/Caramel">Hot Fudge/Caramel
</label>
</div>
<div class="checkbox">
<label>
<input name="food" type="checkbox" value="Other">Other
</label>
</div>
<input name="Submit" type="Submit" value="Submit">
<div id="r">
</div>
</form>

Related

How do I validate "textarea" after checkbox is checked with javascript

I've made a form with few questions. Each question has checkboxes or radio buttons, depending on what type of question it is (how many answers can there be).
Then I've started making a validation function, to be able to check if the user went through the whole form.
I am unsure how to make a validation function that would only trigger if a certain answer is picked (certain checkbox is checked, would trigger the function to check for textarea and check its content).
The code I've got so far can be found here.
The code is also available below:
// main function for checking the validation of answer
function Validation() {
if(!ValidateForm()) {
document.getElementById("errorBox").innerHTML = "Please check that you correctly answered the question";
return false;
} else {
document.getElementById("errorBox").innerHTML = "";
return true
}
}
// will check the checkbox to see if checked,
// the "console.log" is there just because of previous problems, don't mind it
function ValidateForm() {
var k = document.getElementsByName('Knowledge');
for (var l = 0; l<k.length; l++) {
if (k[l].checked) {
console.log(k[l])
return true;
}
}
}
// this was supposed to be the code to do the following:
// if the checkbox is checked, it would check for textarea
// if the textarea is there, check if it has any content
// if not, return false ---> sends message from the main function
var k = document.getElementsByName('Knowledge');
for(var i = 0; i<k.length; i++) {
if (k[6].checked) {
}
}
<form id="frmForm" name="frmForm" action="#" method="post" onsubmit="return Validation()">
<div class="row" style="margin-top: 20px;">
<div class="col-sm-12">
<div class="form-group">
<p>
<b>3. This is a question, Lorem ipsum dolor sit amet?</b>
</p>
<p style="margin-left: 16px;">
(please choose one or more answers to continue)
</p>
<div style="margin-left: 35px;">
<input type="checkbox" id="Knowledge1" name="Knowledge" value="physical" >
<label for="Knowledge1" style="font-weight:normal">answer 1<br>
<input type="checkbox" id="Knowledge2" name="Knowledge" value="music" >
<label for="Knowledge2" style="font-weight:normal">answer 2<br>
<input type="checkbox" id="Knowledge3" name="Knowledge" value="nature" >
<label for="Knowledge3" style="font-weight:normal">answer 3</label><br>
<input type="checkbox" id="Knowledge4" name="Knowledge" value="society" >
<label for="Knowledge4" style="font-weight:normal">answer 4</label><br>
<input type="checkbox" id="Knowledge5" name="Knowledge" value="other" >
<label for="Knowledge5" style="font-weight:normal">answer 5 + explain
<input type="text" placeholder=" . . ." border=""/></label><br>
</div>
</div>
</div>
</div>
<div class="row" style="margin-top: 50px">
<div class="col-sm-3 col-sm-offset-3">
<div class="form-group">
<button type="submit" id="Submit" name="Submit" class="btn btn-default">! ANSWER !</button>
</div>
</div>
</div>
<div id="errorBox" style="margin-bottom:50px; color: red"></div>
</form>
If you want to keep it generic, add a data attribute to the checkboxes that required additional text and make your validation check that data attribute:
<input type="checkbox" id="Knowledge5" name="Knowledge" value="other" data-explain="Knowledge5text">
<input id="Knowledge5text" type="text" placeholder="..." border=""/>
.
if (checkboxElement.dataset.explain) {
console.log('answer requires an explanation');
var textFieldElement = document.getElementById(k[i].dataset.explain);
if (!textFieldElement .value) {
console.log('no answer found:', textFieldElement .value);
return false;
}
}
Here is the complete example. Side note: Avoid single-character variable names for anything but loop variables, it makes understanding code more difficult
// main function for checking the validation of answer
function Validation() {
if(!ValidateForm()) {
document.getElementById("errorBox").innerHTML = "Please check that you correctly answered the question";
return false;
} else {
document.getElementById("errorBox").innerHTML = "";
return true
}
}
// will check the checkbox to see if checked,
// the "console.log" is there just because of previous problems, don't mind it
function ValidateForm() {
var k = document.getElementsByName('Knowledge');
for (var i = 0; i < k.length; i++) {
if (k[i].checked) {
if (k[i].dataset.explain) {
console.log('answer requires an explanation');
var textField = document.getElementById(k[i].dataset.explain);
if (!textField.value) {
console.log('no answer found:', textField.value);
return false;
}
}
return true;
}
}
}
<form id="frmForm" name="frmForm" action="#" method="post" onsubmit="return Validation()">
<div class="row" style="margin-top: 20px;">
<div class="col-sm-12">
<div class="form-group">
<p>
<b>3. This is a question, Lorem ipsum dolor sit amet?</b>
</p>
<p style="margin-left: 16px;">
(please choose one or more answers to continue)
</p>
<div style="margin-left: 35px;">
<input type="checkbox" id="Knowledge1" name="Knowledge" value="physical" >
<label for="Knowledge1" style="font-weight:normal">answer 1<br>
<input type="checkbox" id="Knowledge2" name="Knowledge" value="music" >
<label for="Knowledge2" style="font-weight:normal">answer 2<br>
<input type="checkbox" id="Knowledge3" name="Knowledge" value="nature" >
<label for="Knowledge3" style="font-weight:normal">answer 3</label><br>
<input type="checkbox" id="Knowledge4" name="Knowledge" value="society" >
<label for="Knowledge4" style="font-weight:normal">answer 4</label><br>
<input type="checkbox" id="Knowledge5" name="Knowledge" value="other" data-explain="Knowledge5text">
<label for="Knowledge5" style="font-weight:normal">answer 5 + explain
<input id="Knowledge5text" type="text" placeholder=" . . ." border=""/></label><br>
</div>
</div>
</div>
</div>
<div class="row" style="margin-top: 50px">
<div class="col-sm-3 col-sm-offset-3">
<div class="form-group">
<button type="submit" id="Submit" name="Submit" class="btn btn-default">! ANSWER !</button>
</div>
</div>
</div>
<div id="errorBox" style="margin-bottom:50px; color: red"></div>
</form>

Issue with using .extend on array inside a for loop

I have a set of checkboxes, and based on which items are selected, different upload fields will display. To facilitate this, I want to dynamically create an array that contains all the classes I want to fetch (without duplication).
I have created an object with the details:
var uploadReq = {
a: [".document-2"],
b: [".document-1", ".document-3"],
c: [".document-1"],
d: [".document-2", ".document-3"],
e: [],
f: [".document-3"]
};
In this example, if someone chose Category A and Category B, we should end up with an array something like [".document-2", ".document-1", ".document-3"] (order is unimportant).
I have an event listener like this:
$("#client-cat").change(function() {
var arr = $("#client-cat input");
var classes = [];
for(i=0; i<arr.length; i++) {
if(arr[i].checked) {
var value = arr[i].value;
var arr2 = uploadReq[value];
$.extend(classes, arr2);
}
};
console.log(classes);
})
HTML:
<form>
<div class="segment">
<label for="client-cat">Client category:</label>
<div id="client-cat">
<div>
<input type="checkbox" tabindex="0" name="client-cat" value="a">
<label>Category A</label>
</div>
<div>
<input type="checkbox" tabindex="0" name="client-cat" value="b">
<label>Category B</label>
</div>
<div>
<input type="checkbox" tabindex="0" name="client-cat" value="c">
<label>Category C</label>
</div>
<div>
<input type="checkbox" tabindex="0" name="client-cat" value="d">
<label>Category D</label>
</div>
<div>
<input type="checkbox" tabindex="0" name="client-cat" value="e">
<label>Category E</label>
</div>
<div>
<input type="checkbox" tabindex="0" name="client-cat" value="f">
<label>Category F</label>
</div>
</div>
</div>
<div class="segment">
<div class="document-1">
<label for="document-1">Upload a copy of Document 1:</label>
<input type="file" id="document-1" name="1" accept=".pdf">
</div>
<div class="document-2">
<label for="document-2">Upload a copy of Document 2:</label>
<input type="file" id="document-2" name="2" accept=".pdf">
</div>
<div class="document-3">
<label for="document-3">Upload a copy of Document 3:</label>
<input type="file" id="document-3" name="3" accept=".pdf">
</div>
</div>
</form>
However, when I run the code with Category A and Category B checked, I only get [".document-1", ".document-3"].
I believe what is happening is that every time the for loop restarts, it is reverting to the original value for classes, instead of taking the value from the end of the loop and restarting it.
Research/attempted fixes:
Looked at this thread which discusses using $.extend to solve a similar problem (e.g. combine two arrays without catching duplicates)
Tested to see if it's a scoping issue by trying the code:
$("#client-cat").change(function() {
var arr = $("#client-cat input");
var classes = [];
for(i=0; i<arr.length; i++) {
if(arr[i].checked) {
classes.push("bob");
}
}
console.log(classes);
})
But the above logs an array with as many "bob"s as there are checkboxes, so I don't think it's an issue with the scope of class.
Considered other methods of combining the data. Example: push works, but I end up with arrays inside arrays, which isn't what I want. Example: map might do it, but doesn't clear out duplicates.
JSFiddle here.
$.extend is not the right way to append arrays. It merges objects by adding properties in the second (or later) object that aren't in the first object. But when you use arrays, both arrays have a 0 property, so the first element of the second array is not added to the first array.
The function for appending arrays is concat. It doesn't modify the array in place, you need to assign back to the variable.
$("#client-cat").change(function() {
var arr = $("#client-cat input:checked");
var classes = [];
arr.each(function() {
classes = classes.concat(uploadReq[this.value]);
});
console.log(classes);
})
jQuery.extend()
First param: An object that will receive the new properties if additional objects are passed in or that will extend the jQuery namespace if it is the sole argument.
Therefore, with arrays you're going to face problems.
You can use this approach: classes = [ ...classes, ...arr2]
var uploadReq = {
a: [".document-2"],
b: [".document-1", ".document-3"],
c: [".document-1"],
d: [".document-2", ".document-3"],
e: [],
f: [".document-3"]
};
$("#client-cat").change(function() {
var classes = [];
var arr = $("#client-cat input");
for (var i = 0; i < arr.length; i++) {
if (arr[i].checked) {
var value = arr[i].value;
var arr2 = uploadReq[value];
classes = [ ...classes, ...arr2];
}
}
console.log(classes);
});
.segment {
margin-bottom: 2em;
}
<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js"></script>
<!DOCTYPE html>
<html>
<head>
<link rel="stylesheet" type="text/css" href="checkbox-display.css">
</head>
<body>
<form>
<div class="segment">
<label for="client-cat">Client category:</label>
<div id="client-cat">
<div>
<input type="checkbox" tabindex="0" name="client-cat" value="a">
<label>Category A</label>
</div>
<div>
<input type="checkbox" tabindex="0" name="client-cat" value="b">
<label>Category B</label>
</div>
<div>
<input type="checkbox" tabindex="0" name="client-cat" value="c">
<label>Category C</label>
</div>
<div>
<input type="checkbox" tabindex="0" name="client-cat" value="d">
<label>Category D</label>
</div>
<div>
<input type="checkbox" tabindex="0" name="client-cat" value="e">
<label>Category E</label>
</div>
<div>
<input type="checkbox" tabindex="0" name="client-cat" value="f">
<label>Category F</label>
</div>
</div>
</div>
<div class="segment">
<div class="document-1">
<label for="document-1">Upload a copy of Document 1:</label>
<input type="file" id="document-1" name="1" accept=".pdf">
</div>
<div class="document-2">
<label for="document-2">Upload a copy of Document 2:</label>
<input type="file" id="document-2" name="2" accept=".pdf">
</div>
<div class="document-3">
<label for="document-3">Upload a copy of Document 3:</label>
<input type="file" id="document-3" name="3" accept=".pdf">
</div>
</div>
</form>
<script src="http://code.jquery.com/jquery-3.3.1.min.js" integrity="sha256-FgpCb/KJQlLNfOu91ta32o/NMZxltwRo8QtmkMRdAu8=" crossorigin="anonymous">
</script>
</body>
</html>

Create a report for a form javascript

Hope someone can help.
I have a dynamically generated form that ends up looking like this
<form>
<header><h2 id="title">This is a Survey Title</h2></header>
<ul class="Question_list">
<li class="question">
<div id="sm_survey_question_0">
<fieldset>
<div class="question_text">is this a test?</div>
<input type="radio" name="0" value="1">yes<br>
<input type="radio" name="0" value="2">no<br>
<input type="radio" name="0" value="3">maybe<br>
</fieldset>
</div>
</li>
<li class="question">
<div id="sm_survey_question_1">
<fieldset>
<div class="question_text">Is Batman the best?</div>
<input type="radio" name="1" value="1">yes<br>
<input type="radio" name="1" value="2">no<br>
</fieldset>
</div></li>
<li>
<div id="sm_survey_question_2">
<fieldset>
<div class="question_text">best colors</div>
<input type="radio" name="2" value="1">red<br>
<input type="radio" name="2" value="2">blue<br>
<input type="radio" name="2" value="3">green<br>
</fieldset>
</div>
</li>
</ul>
</form>
and I would like that when the submit button is clicked i can generate a "report", a string would work with the question and the answers selected.
I cant wrap my mind around how to do that.
so far im able to cycle through the questions, check what answers are checked but its the end when i have to create a sting with the questions + its checked
module.createReport = function() {
console.log('reporting');
var questions = document.getElementsByClassName('question');
console.log(questions.length+1,"questions");
var StringAnswers="";
for (var i = questions.length ; i >= 0; i--) {
var textq= document.getElementById('sm_survey_question_'+i).getElementsByClassName("question_text")[0].innerHTML;
var answers = document.getElementById('sm_survey_question_'+i).getElementsByTagName('input');
for (var j = answers.length-1; j >= 0; j--) {
if (answers[j].checked) {
var isanswerC= answers[j].value;
};
var conc= textq+" "+isanswerC;
StringAnswers.concat(conc);
};
};
console.log(conc);
};

jQuery - Uncheck other checkboxes if a specific checkbox is selected by user

I would like to uncheck all the checkboxes that are presently selected if a specific checkbox is selected by the user.
Example:
<div>
<label for="foo">
<input type="checkbox" name="meh" id="foo" checked> foo
</label>
</div>
<div>
<label for="bar">
<input type="checkbox" name="meh" id="bar" checked> bar
</label>
</div>
<div>
<label for="foobar">
<input type="checkbox" name="meh" id="foobar"> foobar
</label>
</div>
<div>
<label for="barfoo">
<input type="checkbox" name="meh" id="barfoo" checked> barfoo
</label>
</div>
<div>
<label for="omgwtfbbq">
<input type="checkbox" name="meh" id="omgwtfbbq"> omgwtfbbq
</label>
</div>
If the user selects "omgwtfbbq" checkbox, I would like all the other boxes that might be checked to be unchecked and have the "omgwtfbbq" be the only one checked.
for the label instead of id I think you need for
<div>
<label for="foo">
<input type="checkbox" name="foo" id="foo" checked /> foo
</label>
</div>
<div>
<label for="bar">
<input type="checkbox" name="bar" id="bar" checked /> bar
</label>
</div>
<div>
<label for="foobar">
<input type="checkbox" name="foobar" id="foobar" /> foobar
</label>
</div>
<div>
<label for="barfoo">
<input type="checkbox" name="barfoo" id="barfoo" checked /> barfoo
</label>
</div>
<div>
<label for="omgwtfbbq">
<input type="checkbox" name="omgwtfbbq" id="omgwtfbbq" /> omgwtfbbq
</label>
</div>
then
var $others = $('input[type="checkbox"][name="meh"]').not('#omgwtfbbq')
$('#omgwtfbbq').change(function () {
if (this.checked) {
$others.prop('checked', false)
}
});
$others.change(function () {
if (this.checked) {
$('#omgwtfbbq').prop('checked', false)
}
})
Demo: Fiddle
Note: I'll add a common class to all the input elements which has to be affected by omgwtfbbq and change var $others = $('#foo, #bar, #foobar, #barfoo') to var $others = $('.myclassoninput')
Live demo (click).
$('#omgwtfbbq').click(function() {
$('input:checkbox').not(this).attr('checked', false);
});
Also note that you're re-using id's. Id's should only be used once in a document.
If you choose not to give each checkbox a sequential IDs so that you can use an array, here's a solution:
Place all your controls in a div, with an ID "checkgroup".
Then the JavaScript function goes:
function checkone(d){
if (!d.checked) return; //if it's unchecked, then do nothing
var group=document.getElementById('checkgroup');
var os=group.getElementsByTagName('input');
for (var i=0;i<os.length;i++){
if (os[i].checked&&os[i]!=d) os[i].checked=false;
}
}
Now you can call this function in each checkbox
<div id="checkgroup">
<input id="abcd" onclick="checkone(this);">
<input id="xyz" onclick="checkone(this);">
...
</div>
Note how you don't even need to bother with the name, because the object passes in itself.

How can I make this javascript form validation DRYer?

The user has to select one radio from each of three input "categories". If he "submits" without doing so, he gets a warning:
http://jsfiddle.net/bqyvS/
Markup like this:
<form>
<div id="color">
<input type="radio" name="color" id="blue">
<label for="blue">Blue</label>
<input type="radio" name="color" id="red">
<label for="red">Red</label>
<input type="radio" name="color" id="green">
<label for="green">Green</label>
</div>
<div id="shape">
<input type="radio" name="shape" id="square">
<label for="square">Square</label>
<input type="radio" name="shape" id="circle">
<label for="circle">Circle</label>
<input type="radio" name="shape" id="triangle">
<label for="triangle">Triangle</label>
</div>
<div id="size">
<input type="radio" name="size" id="small">
<label for="small">Small</label>
<input type="radio" name="size" id="medium">
<label for="mediume">Medium</label>
<input type="radio" name="size" id="large">
<label for="large">Large</label>
</div>
</form>
<a id="link" href="#">click me to "submit"</a>
<p id="warning"></p>​
Javascript:
$('#link').on('click', function() {
if (!$('#color input[type=radio]:checked').length) {
$('#warning').html("Oops! Please choose a color!");
}
else if(!$('#shape input[type=radio]:checked').length) {
$('#warning').text("Oops! Please choose a shape!");
}
else if(!$('#size input[type=radio]:checked').length) {
$('#warning').text("Oops! Please choose a size!");
}
});
This is a simplified version of a larger piece of code. How can I rewrite the conditional more efficiently so that I'm not verbosely checking each input name? (There should only be one "warning" displayed per "submit", even if multiple input name categories aren't checked.) Editing the markup would be okay.
Thanks!
When applying behavior to similar groups, you should start thinking about classes instead of ids, in this solution, you don't need a separate data-name but I believe it's better to have data separate from html id, but you could use this.id if you prefer
<form>
<div id="color" class="selection-group" data-name="color">
<input type="radio" name="color" id="blue">
<label for="blue">Blue</label>
<input type="radio" name="color" id="red">
<label for="red">Red</label>
<input type="radio" name="color" id="green">
<label for="green">Green</label>
</div>
<div id="shape" class="selection-group" data-name="square">
<input type="radio" name="shape" id="square">
<label for="square">Square</label>
<input type="radio" name="shape" id="circle">
<label for="circle">Circle</label>
<input type="radio" name="shape" id="triangle">
<label for="triangle">Triangle</label>
</div>
<div id="size" class="selection-group" data-name="size">
<input type="radio" name="size" id="small">
<label for="small">Small</label>
<input type="radio" name="size" id="medium">
<label for="mediume">Medium</label>
<input type="radio" name="size" id="large">
<label for="large">Large</label>
</div>
</form>
<a id="link" href="#">click me to "submit"</a>
<p id="warning"></p>​
Javascript:
$('#link').on('click', function() {
$('.selection-group').each(function() {
if(!$(this).find('input[type=radio]:checked').length) {
$('#warning').html("Oops! Please choose a "+ $(this).data('name') +"!");
return false;
}
});
});
function validationCheck() {
var isValid = true,
errorText = "";
$("form div").each( //get the divs that hold the radios and loop
//$("#color, #shape, #size").each( //could do it by ids of the divs also
function(){
var div = jQuery(this), //div reference
isChecked = div.find('input[type="radio"]:checked').length>0; //see if we have anything selected
if (!isChecked) { //if no selections, show error message
isValid = false; //set validation to false
errorText = "Oops! Please choose a " + div.prop("id") + "!"; //build error message
return false; //exit each loop
}
}
);
$('#warning').text(errorText); //set error message
return isValid;
}
$('#link').on('click', function(){
$('#color, #shape, #size').each(function(i, ele){
if($(this).find('input:checked').length == 0)
$('#warning').text("Oops! Please choose a " + this.id + "!");
});
});
jsFiddle
You may want to consider generating a warning message in the case a user does not select any inputs or only 1 input.
In this example, a user will recieve a message similar to Oops! Please choose a color, and shape!
$('#link').on('click', function(){
var msgs = [];
$('#color, #shape, #size').each(function(i, ele){
if($(this).find('input:checked').length == 0)
msgs.push(this.id);
});
if(msgs.length > 0)
$('#warning').text("Oops! Please choose a " + msgs.join(", and "));
});
jsFiddle

Categories