HTML form javascript to associate question, answer and feedback - javascript

I have a language quiz in an HTML form When the user checks their entry, feedback is inserted into cell in the form of a tick or cross icon . My problem is that the feedback is always inserted into the first td whether the first or second question is answered and checked. Question and appropriate answer are associated with elementNo: I can't figure out how to associate the "mark" cell with the its answer and question
<SCRIPT>
//Define the answers.
Answer = new Array( "Die Maus ist weiss.", "",
"Auf Wiedersehen!");
//inserts icon, however only in the first element named "mark".
// Somehow needs to select correct place according to element number
function itemfeedback (elementNo)
{
if (document.E1a.elements[elementNo].value == "")
{
alert("You must type an answer!");
}
else if (document.E1a.elements[elementNo].value == Answer[elementNo])
{
document.getElementById("mark").innerHTML = "<img src='correct.jpg'>";
}
else
{
document.getElementById("mark").innerHTML = "<img src='incorrect.jpg'>";
}
}
</SCRIPT>
</HEAD>
<BODY>
<FORM NAME="E1a" accept-charset="ISO-8859-1" onReset="return confirm('Clear entries? Are you sure?')">
<HR>
<H3>
translate, remembering punctuation and capitalisation...
</H3>
<table>
<tr>
<td>1. The mouse is white.</td>
<td><INPUT TYPE="TEXT" NAME="Q1" SIZE=50 MAXLENGTH=50></td>
<td><INPUT TYPE="button" id ="check_button" VALUE="check..." NAME="B1" onClick="itemfeedback(0)"></td>
<td id="mark"></td>
</tr>
<tr>
<td>2. Good-bye!</td>
<td><INPUT TYPE="TEXT" NAME="Q2" SIZE=50 MAXLENGTH=50></td>
<td><INPUT TYPE="button"id ="check_button" VALUE="check..." NAME="B2" onClick="itemfeedback(2)"></td>
<td id="mark"></td>
</tr>
</table>
<hr>
<INPUT TYPE="RESET" id ="reset_fields" VALUE="Clear Entries">
</CENTER>
</FORM>
</BODY>
</HTML>
I hope that my question is clear and that someone will help.

Quick Answer
ID's are intended to be unique within a HTML document according to HTML5 specs. Because of this, all instances of an ID after the first occurrence are ignored by JavaScripts "getElementById" function. A more proper way to select multiple DOM elements is to use the "class" attribute, like this:
<td class="mark"></td>
...
<td class="mark"></td>
And reference it using JavaScript, using "getElementsByClassName"
document.getElementsByClassName('mark')
More Helpful Answer
I would make a couple more suggestions, to make your code a bit more dynamic, and functional. I have inserted comments in the code below to explain the changes/suggestions I have.
<html>
<head>
<script>
// We will use an object instead of an array, so that we can reference the answers by a string, rather then an integer.
// Also, any time a NEW variable is defined, it should be prefaced with "let" or "const" for >= ES2015, or "var" for < ES2015 (see https://codeburst.io/javascript-wtf-is-es6-es8-es-2017-ecmascript-dca859e4821c for details on the different script versions)
const answer = {
Q1: "Die Maus ist weiss.",
Q2: "Auf Wiedersehen!"
};
// itemfeedback function is now passing the input id, rather than the index
function itemfeedback (id) {
// This will get the input, associated with the button
let input = document.getElementById(id),
// This will be the ID of the mark element that is associated with the submitted input
markId = "mark" + id,
// This is the mark element assocaited with the submitted input
mark = document.getElementById(markId);
if (input.value == "") {
alert("You must type an answer!");
}
// Since we have assigned the answers to an object, and gave each of the answers indexes to match the input ids, we can find the answer by that
else if (input.value == answer[id]){
mark.innerHTML = "<img src='correct.jpg'>";
} else {
mark.innerHTML = "<img src='incorrect.jpg'>";
}
}
</script>
</head>
<body>
<form NAME="E1a" accept-charset="ISO-8859-1" onReset="return confirm('Clear entries? Are you sure?')">
<HR>
<H3>
translate, remembering punctuation and capitalisation...
</H3>
<table>
<tr>
<td>1. The mouse is white.</td>
<!-- Gave input ID of "Q1" -->
<td><input TYPE="TEXT" NAME="Q1" SIZE=50 MAXLENGTH=50 id="Q1"></td>
<!-- Changed id to class, since it is non-unique -->
<td><input TYPE="button" class="check_button" value="check..." NAME="B1" onClick="itemfeedback('Q1')"></td>
<!-- We will give this an ID that can be associated with it's related inputs name attribute -->
<td id="markQ1"></td>
</tr>
<tr>
<td>2. Good-bye!</td>
<!-- Gave input ID of "Q2" -->
<td><input TYPE="TEXT" NAME="Q2" SIZE=50 MAXLENGTH=50 id="Q2"></td>
<!-- Passed ID to onChange handler, instead of index. Also hanged id to class, since it is non-unique -->
<td><input TYPE="button" class="check_button" value="check..." NAME="B2" onClick="itemfeedback('Q2')"></td>
<!-- We will give this an ID that can be associated with it's related inputs name attribute -->
<td id="markQ2"></td>
</tr>
</table>
<hr>
<input TYPE="RESET" id="reset_fields" value="Clear Entries">
</center>
</form>
</body>
</html>
EDIT for Form Reset
Place this function to remove images from form onReset:
<!-- We are now calling a function to be executed, and the returned value of the function will determine if the form itself is cleared. A negative blue will not, a positive value will -->
<form NAME="E1a" accept-charset="ISO-8859-1" onReset="return clearForm(this)">
function clearForm (form) {
// Get option that is pressed
var clear = confirm('Clear entries? Are you sure?');
// If positive option is clicked, the form will be reset
if (clear) {
// This will select all images within the document
var markImgs = document.getElementsByTagName('img');
// Iterates through each image, and removes it from the dom
while (markImgs[0]) markImgs[0].parentNode.removeChild(markImgs[0])
}
return clear;
}

Related

How to use checked input values used for math as part of cloned div elements

I have written a script that clones a certain div as required by the user. Within the div there are three checkbox input options and each option as a numeric value. I want the script to allow the user to select a checkbox and then the value will be reflected in another input space and each value that are added will be separated by a comma.
The tricky part is that it should be done for each clone, and that each checkbox has the same class name to which the script should be written. I realize that using unique id's would be better, but I would like it that a for loop could do it for any number of checkboxes under the specific class.
Here is the html script:
<style>
.hidden {
display: none;
}
</style>
<body>
<h2>Test</h2>
<button id="add">Add</button>
<div class="test hidden">
<div class="user_input1">
<label>Input1</label>
<input class="input1" type="text" required>
<label>Input2</label>
<input type="text" name="value2" required>
<div class="user_input2">
<table>
<thead>
<tr>
<th>Pick Option</th>
</tr>
</thead>
<tbody>
<tr id="append">
<td><input class="test" type="checkbox" name="test" value="1">Test1</td>
<td><input class="test" type="checkbox" name="test" value="2">Test2</td>
<td><input class="test" type="checkbox" name="test" value="3">Test3</td>
</tr>
</tbody>
</table>
<input type="text" id="insert" name="check">
<button class="hidden" id="testbtn">Calc</button>
</div>
</div>
</div>
<form action="server/server.php" method="POST">
<div class="paste">
</div>
<button type="submit" name="insert_res">Submit</button>
</form>
</body>
And my attempt for the jQuery:
$(document).ready(function() {
var variable = 0
$("#add").click(function() {
var element = $(".test.hidden").clone(true);
element.removeClass("hidden").appendTo(".paste:last");
});
});
$(document).ready(function(event) {
$(".test").keyup(function(){
if ($(".test").is(":checked")) {
var test = $(".test").val();
};
$("#insert").val(test);
});
$("#testbtn").click(function() {
$(".test").keyup();
});
});
I think a for loop should be used for each checkbox element and this to specify each individual clone, but I have no idea where or how to do this. Please help!
I am assuming you already know how to get a reference to the dom element you need in order to append, as well as how to create elements and append them.
You are right in that you can loop over your dataset and produce dom elements with unique id's so you can later refer to them when transferring new values into your input.
...forEach((obj, index) => {
(produce tr dom element here)
(produce three inputs, give all unique-identifier)
oneOfThreeInputs.setAttribute('unique-identifier', index); // can set to whatever you want, really
(proceed to creating your inputs and appending them to the tr dom element)
targetInputDomElementChild.setAttribute('id', `unique-input-${index}`); // same here, doesn't have to be class
});
Observe that I am using template strings to concat the index number value to the rest of the strings. From then on, you can either reference the index to refer to the correct input or tr using jquery in your keyUp event handler:
function keyUpEventHandler($event) {
const index = $(this).attr('unique-identifier');
const targetInput = $(`#unique-input-${index}`)
// do stuff with targetInput
}
I have created a fiddle to show you the route you can take using the above information:
http://jsfiddle.net/zApv4/48/
Notice that when you click an checkbox, in the console you will see the variable number that designates that set of checkboxes. You can use that specific number to get the input you need to add to and concat the values.
Of course, you still need to validate whether it is being checked or unchecked to you can remove from the input.

Appear a textbox only when the checkbox is checked and not save the field in the database if is not checked

Sorry for english grammar, not my native language.
I want to show a textbox only when the checkbox is checked. So, i have this code:
HTML
<table>
<tr>
<td>
<input type = "checkbox" id="NCFtxt" onclick="obtenerNCF()"> Marcar casilla para generar Comprobante Fiscal
</td>
</tr>
<tr>
<td>
NCF: <input readonly="readonly" name= "txtNCF" type= "text" id= "txtNCF" value= "<?php echo $cobro->ncf; echo $ncf; ?>" />
</td>
</tr>
</table>
JAVASCRIPT
<script language="javascript">
$("#txtNCF").hide();
function obtenerNCF() {
var chequear = document.getElementById("NCFtxt");
if (chequear.checked == true){
$("#txtNCF").show();
} else {
$("#txtNCF").hide();
}
}
</script>
So, this is "working", is hiding the field when the checkbox is checked, but still saving the data at the Database. How can I do to not only hide the field, but neither saved in the database? I was trying some things but none worked, this seems simple, but it confusing me
If you don't want to save something based on a checkbox... look at the $_POST if the checkbox has a value or not (if not, then it was not checked). Then save or not-save the extra data.
Give the checkbox a name and value:
<input type="checkbox" name="NCFtxt_checkbox" value="1" id="NCFtxt" onclick="obtenerNCF()">
And in PHP look for it:
if ( empty($_POST['NCFtxt_checkbox']) ) {
// dont save extra data
} else {
// else do save the extra data
}
A second solution is to use a lot of javascript, and when the checkbox is UN-checked, you clear-out the content of the other text box as you hide it. That way it would be submitted 'emtpy' to begin with.

Initially Hiding and then Dynamically Adding and Removing Rows

I'm working on a request form. It needs to list the study team members on a research study besides the PI and submitter of the form. However, some studies will have no additional team members so I would like the row to remain hidden until someone clicks the Add Team Member button.
What's working:
1. I've got the element hidden on initially loading the page.
2. Clicking add rows adds the correct rows.
3. Clicking remove will remove a row.
Current problems:
1. If someone adds a team member then removes all the team members, clicking add team member will not add a row.
2. When the element is hidden on initial page load, the first time the Add Team Member button is clicked it adds two rows.
Here's my current code with only the relevant section of the form.
<!DOCTYPE html>
<html>
<head>
<link rel="stylesheet" href="assets/css/test.css" />
<script type="text/javascript" src="http://code.jquery.com/jquery-latest.min.js"></script>
<script type="text/javascript">
function addTableRow(jQtable){
jQtable.each(function(){
var tds = '<tr>';
jQuery.each($('tr:last td', this), function() {tds += '<td>'+$(this).html()+'</td>';});
tds += '</tr>';
if($('tbody', this).length > 0){$('tbody', this).append(tds);
}else {$(this).append(tds);}
});
}
</script>
<script>
function myDeleteFunction() {
document.getElementById("stmember").deleteRow(0);
}
</script>
<script type="text/javascript">
$(function() {
$('#add').click(function() {
$('#stmember').show();
});
});
</script>
<style>
#stmember {
display: none
}
</style>
</head>
<body>
<h3><strong>Other Study Team Members:</strong></h3>
<FORM>
<table id="stmember">
<tr>
<td>Name:
<label for="namest1"></label>
<input type="text" name="namest1" id="namest1" placeholder="First Name, Last Name" />
</td>
<td>JHED ID:
<label for="jhedst1"></label>
<input type="text" name="jhedst1" id="jhedst1" />
</td>
<td>Email:
<label for="emailst1"></label>
<input type="email" name="emailst1" id="emailst1" placeholder="you#example.com" />
</td>
</tr>
</table>
<CENTER>
<button type="button" id="add" onclick="addTableRow($('#stmember'));">Add Study Team Member</button>
<button type="button" onclick="myDeleteFunction()">Remove Study Team Member</button>
</CENTER>
</FORM>
</body>
</HTML>
Here are a couple solutions for you:
Solution 1
Store the HTML of the row in your addTableRow function within a variable. That way you can use tokens for the input IDs to ensure they are unique. Also, you won't have to provide the first row in your HTML, as it will be created through your JS function. Something like:
var template = "<tr><td>Name:<label for="namest1"></label><input type="text" name="namest!!TOKEN!!" id="namest!!TOKEN!!" placeholder="First Name, Last Name" /></td><td>JHED ID:<label for="jhedst1"></label><input type="text" name="jhedst!!TOKEN!!" id="jhedst!!TOKEN!!" /></td><td>Email:<label for="emailst1"></label><input type="email" name="emailst!!TOKEN!!" id="emailst!!TOKEN!!" placeholder="you#example.com" /></td></tr>";
Solution 2
Use a templating engine like jsRender or Mustache.
Conclusion
The cleanest method would be to use a templating engine, if you're game for that. But using a string to store the template within your function will work.
If you're using jQuery, I'd fully commit to using that instead of mixing vanilla JS, as with jQuery you can use clone and remove effectively for what you're trying to achieve. Also, if you plan on submitting this as a form, please be sure to add [] to your input names so you can parse each row properly as the names are the same on the input fields. Please see the below snippet:
function addTableRow() {
var $tableRow = $('tr.model-row:first-child');
var $clonedRow = $tableRow.clone().show();
$('#stmember').append($clonedRow);
}
function myDeleteFunction() {
var $memberTRs = $('tr', '#stmember');
// If rowcount === 1, hide first row, don't remove it!!
var rowCount = $memberTRs.length;
if (rowCount === 1) {
$('tr.model-row:first-child').hide();
return;
}
$memberTRs.last().remove();
}
jQuery(function() {
$('#delete').click(function() {
myDeleteFunction();
});
$('#add').click(function() {
addTableRow();
});
});
.model-row {
display: none;
}
<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js"></script>
<body>
<h3><strong>Other Study Team Members:</strong></h3>
<FORM>
<table id="stmember">
<tbody>
<tr class="model-row">
<td>Name:
<label for="namest1"></label>
<input type="text" name="namest1[]" id="namest1" placeholder="First Name, Last Name" />
</td>
<td>JHED ID:
<label for="jhedst1"></label>
<input type="text" name="jhedst1[]" id="jhedst1" />
</td>
<td>Email:
<label for="emailst1"></label>
<input type="email" name="emailst1[]" id="emailst1" placeholder="you#example.com" />
</td>
</tr>
</tbody>
</table>
<CENTER>
<button type="button" id="add">Add Study Team Member</button>
<button type="button" id="delete">Remove Study Team Member</button>
</CENTER>
</FORM>
</body>
When you create a row, you use the last existing row to create it. But if you remove all the row you lose your example of row.
You can easily fix your problem by checking when you remove a Row, if it's the last one, add a new row before remove the last one.

JS validation troubles and some more gimmicks

I've already have validated my form using php but I would like to change it to use javascript.For some reason it doesn't seem to work, and I cannot understand why.
<form name="adminFormNewMember" method="post" action=<?php echo htmlspecialchars($_SERVER["PHP_SELF"]);?>>
<table id="tableNewUser">
<tr>
<td>First Name </td>
<td><input type="text" id="firstname" onblur="allLetter()" required autofocus></td>
</tr>
</table>
</form>
---------------------
<script>
function allLetter()
{
var text = document.getElementById("firstname");
var letters = /^[A-Za-z]+$/;
if(text.value.match(letters))
{
return true;
}
else
{
alert("message");
return false;
}
}
</script>
Obviously the form contains more stuff, I've omitted them for the sake of clarity.
Also I'd like to use the same function for more field such as lastname etc, but I don't know how to do that since I'm using the getElementById
Finally, I'd like to just highlight the textfield red for errors, green for correct etc.
Clarification Edit I still need the PHP part I just don't want it to validate. I need the validation to happen for each field onBlur, and then the data to be passed to the php function to be inserted in a DB etc.
Try this :
<!DOCTYPE html>
<html lang="en">
<head></head>
<body>
<form name="adminFormNewMember" method="post" >
<table id="tableNewUser">
<tr>
<td>First Name </td>
<td><input type="text" id="firstname" onblur="allLetter(this.id)" required autofocus></td>
</tr>
</table>
</form>
<script>
var allLetter = function(id){
var text = document.getElementById(id).value;
if(text.length ==0 || text.toUpperCase().replace(/[^A-Z]/g, "").length != text.length) alert("Incorrect value")
}
</script>
</body>
</html>
To use your function with several fields, just pass the id as a parameter (this.id), in allLetters function, pass the parameter to getElementById.
It seems your Regexp is not correct (or suffiscient), so first check the field is not empty then check if length of value equals lenngth of value with letters only. If so the field is correct, otherwise go for the alert.
Maybe you should consider using jquery and the validate plugin here witch can save you lot of time
Returning true or false in your sample code is achieving nothing. What you need to do is, depending on whether validation is successful or not, add a CSS class to your input field. This CSS class should handle either background or border for your field to indicate that it did not match the criteria.
Instead of using onblur attribute, create an event listener for the blur event on your form fields. Delegate this listener to transfer control to a function which will take the value inside the event target and validate it. This should make your code more modular and apply to most fields.
Here is some code in basic javascript:
<table id="tableNewUser">
<tr>
<td>First Name </td>
<td><input type="text" id="firstname" class="formFields"></td>
<td>Last Name </td>
<td><input type="text" id="lastname" class="formFields"></td>
<td>Fathers Name</td>
<td><input type="text" id="fathername" class="formFields"></td>
</tr>
<script>
for(var i=0; i < document.getElementsByClassName("formFields").length ; i++){
document.getElementsByClassName("formFields")[i].addEventListener("blur", function(evt){
var text = evt.target;
var letters = /^[A-Za-z]+$/;
if(text.value.match(letters))
{
evt.target.classList.remove('incorrectField');
evt.target.classList.add('correctField');
}
else
{
evt.target.classList.add('incorrectField');
evt.target.classList.remove('correctField');
}
});
}
<style>
.incorrectField{
background: red;
}
.correctField{
background: green;
}
</style>

place value into input box from query string not working

how can I take the value of a query string and place it into an input box? Currently I have:
<input type="text" name="spouse" id="spouse" value="<script type="text/javascript">
document.write("Name: " + Request.QueryString("spouse"));
</script>"/>
But that only takes the script take and all of its contents and places it into the input box.
I would like to be able to take my query string that is coming from this code:
<tr >
<td><input type="text" name="n1" value="Duck, Donald" /></td>
<td><input type="text" name="n2" value="Daisy" /></td>
<td><input type="button" value="Show" title="Show"
onclick="location.href='example123.html?name=' + escape(this.form.n1.value)+ '&spouse=' + escape(this.form.n2.value);" />
</td>
and have the value for name or spouse appear inside of an input box. What is the proper way to place a value into an input box from a query string?
Request.QueryString is not a native JavaScript function. Use the document.location object and parse out the value you want.
Perhaps use the onload function to perform the action you need. This calls your function once the document has been fully loaded and so you know all tags in the html will exist at this point and be can be referenced properly.
eg.
<html>
<head>
<title>Value Setting</title>
<script type="text/javascript">
window.onload = (function() {
document.getElementById('spouse').value = "one way";
document.forms[0].elements[1].value = "another way";
/* note elements refers to only input children */
});
</script>
</head>
<body>
<form id="myform">
<div>
<input id="first-field" value="first-field" onchange="this.value += ' an example';"/>
</div>
<div>
<p>
<input id="spouse" value="spouse"/>
</p>
</div>
</form>
</body>
</html>
You can't embed elements in attributes as that isn't valid html. Though some attributes can get evaluated as javascript. Namely attributes such as action, onchange, onclick and so on.

Categories