I have the following code that provides me with the calculation that I need, but I want it to work with multiple outputs.
For example, Part A and Part B would have the same jQuery, except Part B may have a different multiplier or calc3, etc.
I will have up to 50 parts and am trying to prevent from having to write 50 rows of jQuery. Is there a way to write this with the (this) variable instead of the ('#id') ?
In the Snippet below, if you add in the Qty, Width, Height, and Depth - you will see the calculation work for Part A, but not Part B because I am trying to make the jQuery calculations simple.
//part1
$("#part1d").keyup(function() {
//part A
$('#part1A').val($('#part1q').val() * 1);
$('#part1AL').val($('#part1w').val() - $('#calc1').val());
$('#part1AW').val($('#part1d').val() - $('#calc2').val());
//part B
$('#part1A').val($('#part1q').val() * 2);
$('#part1AL').val($('#part1w').val() - $('#calc1').val());
$('#part1AW').val($('#part1d').val() - $('#calc2').val());
});
* {
margin: 0;
padding: 0;
float: left;
}
.wrap {
width: 96%;
margin: 2% 2% 500px 2%;
}
.partwrap {}
.partname {
width: 20%;
margin: 1% 20% 1% 0;
}
.partdata {
width: 10%;
}
input {
width: auto;
float: none;
}
.sectiontitle {
color: red
}
.partdescr {
color: purple;
}
.parts {
width: 150px;
}
.values {
display: none;
}
<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js"></script>
<!--values-->
<input class="values" id="calc1" value="1.4375">
<input class="values" id="calc2" value=".25">
<div class="wrap">
<!--part 1-->
<!--part 1 input-->
<div class="partwrap">
<div class="partdescr">
<div class="partname">Part Number: <input id="part1"></div>
<div class="partdata">Qty <input id="part1q"></div>
<div class="partdata">Width <input id="part1w"></div>
<div class="partdata">Height <input id="part1h"></div>
<div class="partdata">Depth <input id="part1d"></div>
</div>
<!--part 1 output-->
<div class="partdescr">
<div class="parts">Part Name</div>
<div class="parts">Qty</div>
<div class="parts">Length</div>
<div class="parts">Width</div>
<div class="parts">Height</div>
</div>
<div>
<div class="parts">Part A</div>
<input id="part1A" class="parts">
<input id="part1AL" class="parts">
<input id="part1AW" class="parts">
<input id="part1AH" class="parts">
</div>
<div>
<div class="parts">Part B</div>
<input id="part1A" class="parts">
<input id="part1AL" class="parts">
<input id="part1AW" class="parts">
<input id="part1AH" class="parts">
</div>
</div>
</div>
First of all your HTML is not valid.
1) Don't use duplicate ID's use classes instead.
2) You've duplicate div closures </div> tags
Once you fix this you should have desired results but, for the overriding bit ie, clac3 or multiplexer you could add an unique IDto that part div and target a specific input
JS
//part1
$("#part1d,#part1q,part1w,part1h").keyup(function () {
//part A
$('.part1A').val($('#part1q').val() * 1);
$('.part1AL').val($('#part1w').val() - $('#calc1').val());
$('.part1AW').val($('#part1d').val() - $('#calc2').val());
//part B
//overriding
$("#partB").find(".part1A").val($('#part1q').val() * 2);
});
HTML
<input class="values" id="calc1" value="1.4375">
<input class="values" id="calc2" value=".25">
<div class="wrap">
<!--part 1-->
<!--part 1 input-->
<div class="partwrap">
<div class="partdescr">
<div class="partname">Part Number: <input id="part1"></div>
<div class="partdata">Qty <input id="part1q"></div>
<div class="partdata">Width <input id="part1w"></div>
<div class="partdata">Height <input id="part1h"></div>
<div class="partdata">Depth <input id="part1d"></div>
</div>
<!--part 1 output-->
<div class="partdescr">
<div class="parts">Part Name</div>
<div class="parts">Qty</div>
<div class="parts">Length</div>
<div class="parts">Width</div>
<div class="parts">Height</div>
</div>
<div>
<div class="parts" id="partA">Part A
<input class="part1A" class="parts">
<input class="part1AL" class="parts">
<input class="part1AW" class="parts">
<input class="part1AH" class="parts">
</div>
<div>
<div class="parts" id="partB">Part B
<input class="part1A" class="parts">
<input class="part1AL" class="parts">
<input class="part1AW" class="parts">
<input class="part1AH" class="parts">
</div>
</div>
</div>
Working Demo
The actual equations didn't make any sense at all so I organized the data in simple categories. It's probably inaccurate but it can be tailored to your specific needs very easily. Each row of inputs results are displayed in 2 outputs. The 2 inputs on top applies to all of the rows 2 outputs. Note that binding the input event to the <form> is better than any keyboard event. The only work needed to be done is adding table rows which is easy since they are identical and even easier should they be dynamically appended (that's entirely a new question).
References
input event
<input type="number">
<output></output>
.valueAsNumber
.toFixed()
Ternary Condition Operator
Dereferencing jQuery Objects
.on()
.each()
.closest()
.find()
Details commented in Demo
Demo
/* Delegate the input event on the <form>
|| On each() output.G and output.O...
|| Find the <tr> they are in by using .closest()
|| Next store all the input valueAsNumber into variables
|| T1 and T2 variables value are determined by ternary
|| conditions (if(condition)) ?) true : false
|| Finally the totals are displayed in the outputs
*/
$("#invForm").on('input', function() {
$('.G,.O').each(function(idx) {
var row = $(this).closest('tr');
var q = row.find('.Q')[0].valueAsNumber;
var w = row.find('.W')[0].valueAsNumber;
var h = row.find('.H')[0].valueAsNumber;
var d = row.find('.D')[0].valueAsNumber;
var m = $('#metric')[0].valueAsNumber;
var i = $('#imperial')[0].valueAsNumber;
var T1 = ($(this).hasClass('G')) ? 1 : 0.578036672;
var T2 = ($(this).hasClass('O')) ? i : m;
var t = (q * w * h * d * T1 * T2).toFixed(2);
$(this).val(t);
});
});
* {
margin: 0;
padding: 0;
}
.inventory {
width: 96%;
table-layout: fixed;
}
td {
border: 1px solid #000
}
.name {
width: 10%;
}
.data,
.total {
width: 10%;
}
input {
width: 12ch;
display: inline-block;
}
input[type=number] {
width: 8ch;
text-align: right;
padding: 0 2px 0 1px
}
output {
text-align: right;
display: inline-block;
width: 6ch;
}
}
<!-- Use a <table> wrapped in a <form> -->
<!-- If data is numbers consider <input type='number'> -->
<!-- <output> tags can handle .val(), .text(), or .html()-->
<form id='invForm'>
<label for='metric'>Metric</label>
<input id="metric" value="1" type='number' step='.01'>
<label for='imperial'>Imperial</label>
<input id="imperial" value="1" type='number' step='.01'>
<table class="inventory">
<thead>
<tr>
<th class='name'>Part Name</th>
<th class="name">Part Number</th>
<th class="data">Qty</th>
<th class="data">Width</th>
<th class="data">Height</th>
<th class="data">Depth</th>
<th class="total">Total Grams</th>
<th class='total'>Total Ounces</th>
</tr>
</thead>
<tbody>
<!--Each row is identical in layout #IDs are not necessary-->
<tr>
<td><input class='part P' value='ChemX'></td>
<td><input class='part N' value='X2k9'></td>
<td><input class='part Q' type='number' step='1' min='0'></td>
<td><input class='part W' type='number' step='.01' min='0'></td>
<td><input class='part H' type='number' step='.01' min='0'></td>
<td><input class='part D' type='number' step='.01' min='0'></td>
<td><output class='part G'></output></td>
<td><output class='part O'></output></td>
</tr>
<!--End of first data row-->
<tr>
<td><input class='part P' value='ChemZ'></td>
<td><input class='part N' value='Zi96u'></td>
<td><input class='part Q' type='number' step='1' min='0'></td>
<td><input class='part W' type='number' step='.01' min='0'></td>
<td><input class='part H' type='number' step='.01' min='0'></td>
<td><input class='part D' type='number' step='.01' min='0'></td>
<td><output class='part G'></output></td>
<td><output class='part O'></output></td>
</tr>
</tbody>
</table>
</form>
<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js"></script>
Related
Update
I am facing an issue with fieldset top border in IE 11.
Description:
I am having a fieldset in my web page. Its legend tag contains a checkbox. And its sub elements are input text fields. I have a JS which changes background color of input fields on checking/Unchecking checkbox present in legend.
Problem:
When background color of input field changes, Fieldset's top border breaks
Can anyone tell me why this is happening?
Sample Code:
function changeBackground() {
document.getElementById("changeit").style.backgroundColor = "red";
}
table .td-left {
width: 60%;
text-align: left;
}
table .td-right {
width: 40%;
text-align: right;
}
<fieldset>
<legend>
<input type="checkbox" onclick="changeBackground()">
<label>Hello</label>
</legend>
<table>
<tr>
<td class="td-right">
<label>Enter Text Here:</label>
</td>
<td class="td-left">
<input type="text" id="changeit">
</td>
</tr>
</table>
</fieldset>
The problem is caused by the checkbox in the legend, obviously. Simply removing the checkbox from the legend makes it work fine.
function changeBackground() {
document.getElementById("changeit").style.backgroundColor = "red";
}
table .td-left {
width: 60%;
text-align: left;
}
table .td-right {
width: 40%;
text-align: right;
}
<fieldset>
<legend>
</legend>
<div style="color:green; height:0; overflow:visible">Booh Booh Booh Booh Booh Booh Booh</div>
<input type="checkbox" onclick="changeBackground()">
<label>Hello</label>
<table>
<tr>
<td class="td-right">
<label>Enter Text Here:</label>
</td>
<td class="td-left">
<input type="text" id="changeit">
</td>
</tr>
</table>
</fieldset>
So what we need to do is make it look like the checkbox is in the legend, without it actually being in there. How about this:
function changeBackground() {
document.getElementById("changeit").style.backgroundColor = "red";
}
table .td-left {
width: 60%;
text-align: left;
}
table .td-right {
width: 40%;
text-align: right;
}
fieldset label[for='flip']::before {
content: ' ☐ ';
}
#flip {
display: none;
}
#flip:checked+fieldset label[for='flip']::before {
content: ' ☑ ';
}
<input type="checkbox" id="flip" onclick="changeBackground()">
<fieldset>
<legend>
<label for="flip">Hello</label>
</legend>
<table>
<tr>
<td class="td-right">
<label>Enter Text Here:</label>
</td>
<td class="td-left">
<input type="text" id="changeit">
</td>
</tr>
</table>
</fieldset>
I want the moment you click on "create row", line 2 is duplicated with the formatting rule: input, select ..
In addition to the first column I want each time to exceed a count of +1 in "count number".
Once I click on Delete Row - it will let me delete the last line except line 1!
Thanks for the helpers!
this is the code:
<!DOCTYPE html>
<html>
<head>
<style>
table, td {
border: 1px solid black;
}
</style>
</head>
<body>
<table id="myTable" class="table table-bordered table-hover" style="font-size: 12px; font-family: Arial;">
<thead>
<tr>
<th style="text-align: right;">השתתפות / שוברים</th>
<th style="text-align: right;">סכ"ה ימים</th>
<th style="text-align: right;">עד תאריך</th>
<th style="text-align: right;">מתאריך</th>
<th style="text-align: right;">שם משפחה</th>
<th style="text-align: right;">שם פרטי</th>
<th style="text-align: right;">מ.א</th>
<th style="text-align: right;">number count</th>
</tr>
</thead>
<tbody>
<tr class="warning">
<td style="text-align: center;">
<select style="font: 12px 'Fira Sans', sans-serif;width: 94px;margin: 0.4rem;text-align-last: right;">
<option value="volvo">השתתפות</option>
<option value="saab">שוברים</option>
</select>
</td>
<td style="text-align: right;"><input type="number" id="fname2" name="firstname" style="font: 12px 'Fira Sans', sans-serif;width: 31px;margin: 0.4rem;text-align-last: center;"></td>
<td style="text-align: right;">
<fieldset>
<div>
<input type="date" name="trip" style="font: 12px 'Fira Sans', sans-serif;width: 113px;margin: 0.4rem;">
</div>
</fieldset>
</td>
<td style="text-align: right;">
<fieldset>
<div>
<input type="date" name="trip" style="font: 12px 'Fira Sans', sans-serif;width: 113px;margin: 0.4rem;">
</div>
</fieldset>
</td><td style="text-align: right;">
<input type="text" id="fname2" name="firstname" style="font: 12px 'Fira Sans', sans-serif;width: 55px;margin: 0.4rem;text-align: right;">
</td>
<td style="text-align: right;">
<input type="text" id="fname2" name="firstname" style="font: 12px 'Fira Sans', sans-serif;width: 52px;margin: 0.4rem;text-align: right;">
</td><td id=check style="text-align: right;">
<input type="number" name="firstname" style="font: 12px 'Fira Sans', sans-serif;width: 64px;margin: 0.4rem;text-align-last: center;">
</td>
<td style="text-align: center;padding-top: 20px;">1
</td>
</tr>
</tbody>
</table>
<br><br>
<p id="demo" onclick="myCreateFunction()">Create row</p> <br>
<p id="demo" onclick="myDeleteFunction()">Delete row</p>
<script>
function myCreateFunction() {
var table = document.getElementById("myTable");
var row = table.insertRow(-1);
var cell1 = row.insertCell(0);
var cell2 = row.insertCell(0);
var cell3 = row.insertCell(0);
var cell4 = row.insertCell(0);
var cell5 = row.insertCell(0);
var cell6 = row.insertCell(0);
var cell7 = row.insertCell(0);
var cell8 = row.insertCell(0);
cell1.innerHTML = 1;
cell2.innerHTML = 2;
cell3.innerHTML = 3;
cell4.innerHTML = 4;
cell5.innerHTML = 5;
cell6.innerHTML = 6;
cell7.innerHTML = 7;
cell8.innerHTML = 8;
}
function myDeleteFunction() {
document.getElementById("myTable").deleteRow(-1);
}
</script>
</body>
</html>
functions down
A fast and easy solution (though maybe not best for long term use) is to have a global variable called something like "depth", start it at let depth = 0 then every time you add a line depth++;, if you remove a line only let it remove the line if(depth >= 0) then you will never be deleting the starting line that already exists.
Another way to do it, and maybe more scalable if this is for a bigger project, is to keep track of the number of lines in an array, each time you add a line, you arr.push(line); when you remove a line you arr.splice(indexofline,1); This gives you the ability to not just track what line you're at, but you could also push information about the line that you could use in later code for expanding the program.
You have some problems in your code.
First of all HTML IDs have to be unique. You are using multiple identical IDs.
Some input fields have the same name. This does not have to be a problem by all means, however, many server-side script languages (e.g. PHP) just overwrite multiple usages and expose just the last one. PHP forms arrays if you use names like <input name="firstname[]">.
A non-empty <title>My Title</title> tag is mandatory in HTML5.
Further more
Documents should declare the charset they are encoded with.
It is always a good idea to have an <html> tag with a lang attribute.
Avoid inline styles. Use stylesheets instead.
Inline event handlers like onclick are old-school. Apply event listeners instead.
There are semantical senseless <div> elements in the cells.
<fieldset> elements containing only one field do not make semantical sense, especially when they devide two related dates. A fieldset enclosing both dates within the same cell could make sense. Use css outline or similar to get the visual effect if you need it.
To get a copy of another row, you can use the cloneNode method.
The number of rows can be determined with table.rows.length. You can use it to fill the 'number count' cell.
If you do need IDs for some reason, they have to be unique per document. This means, you need different IDs even in each row. When copying, you have to change the id in some way - e.g. append the row number.
I have added some demo <label> just to illustrate how to change necessary IDs and the label's for Attribute which is connected to the ID of the according form field. Of course a label in a column with a caption does not really make sense - it's only for teaching purposes.
Copying the first row might be a bad choice, since the entered values are copied as well. More common would be to copy the last entered row. However, there is another alternative. You can use a clean template. <template> elements are not rendered by the browser and thus they are not part of the DOM. You get DOM-like access via the content property.
document.addEventListener('DOMContentLoaded', evt =>
{
const
minRowsPreserved = 2,
byId = document.getElementById.bind(document)
;
function myCreateFunction()
{
let
table = byId("myTable"),
rowCount = table.rows.length,
row = byId('tpl-row').content.firstElementChild.cloneNode(true)
;
// In case you need IDs: Append the row number seperated by '-' to each ID since IDs must be unique.
row.querySelectorAll('[id]').forEach(e => e.id += '-' + rowCount);
// Similar for clickable labels depending on IDs, however, there is no shortcut for the `for` attribute.
row.querySelectorAll('label[for]').forEach(e => e.setAttribute('for', e.getAttribute('for') + '-' + rowCount));
// Content of the last cell becomes the row number.
row.cells[row.cells.length-1].textContent = rowCount;
// now we append the row to the table body after id-conflicts should be resolved
table.tBodies[0].appendChild(row);
}
function myDeleteFunction() {
let table = byId("myTable");
if(minRowsPreserved < table.rows.length)
table.deleteRow(-1);
}
byId('btn-create').addEventListener('click', myCreateFunction);
byId('btn-delete').addEventListener('click', myDeleteFunction);
// add a first row on start
myCreateFunction();
})
#myTable
{
font-size : 12px;
font-family : Arial;
border : 1px solid black;
text-align : center;
margin-bottom: 2em;
}
#myTable td
{
border : 1px solid black;
padding: 0.4rem;
}
#myTable th
{
text-align: right;
}
#myTable input,
#myTable select
{
font : 12px 'Fira Sans', sans-serif;
}
#myTable input[type="text"] { text-align : right; }
#myTable input[type="number"] { text-align-last: center; }
#myTable select { text-align-last: right; }
#myTable input[type="date"] { width : 113px; }
.num1 input { width : 31px; }
.first-name input { width : 55px; }
.last-name input { width : 52px; }
<!DOCTYPE html>
<html lang="he">
<head>
<meta charset="UTF-8">
<title>dynamic table form</title>
<body>
<form method="post">
<table id="myTable" class="table table-bordered table-hover">
<thead>
<tr>
<th>השתתפות / שוברים</th>
<th>סכ"ה ימים</th>
<th>עד תאריך</th>
<th>מתאריך</th>
<th>שם משפחה</th>
<th>שם פרטי</th>
<th>מ.א</th>
<th>number count</th>
</tr>
</thead>
<tbody>
</tbody>
</table>
</form>
<button id="btn-create">Create row</button>
<button id="btn-delete">Delete row</button>
<template id="tpl-row">
<tr class="warning">
<td class="car">
<select id="car" name="car[]" style="width: 94px; text-align-last: right;">
<option value="volvo">השתתפות</option>
<option value="saab">שוברים</option>
</select>
</td>
<td class="num1" > <input type="number" id="num1" name="num1[]" > </td>
<td class="trip-start"> <input type="date" id="trip-start" name="tripstart[]" > </td>
<td class="trip-end" > <input type="date" id="trip-end" name="tripend[]" > </td>
<td class="first-name"> <input type="text" id="first-name" name="firstname[]" > </td>
<td class="last-name" > <input type="text" id="last-name" name="lastname[]" > </td>
<td class="check">
<label for="num2">demo label:</label>
<input type="number" id="num2" name="num2[]" style="width: 64px; text-align-last: center;">
</td>
<td></td>
</tr>
</template>
So I've been searching this site for weeks trying to find a solution to this and have looked at EVERY question asked about getting the sum of input fields or finding the value of start and stop times but none of them solve my issue.
The included snippet shows a time sheet that I currently am able to input the reg (regular) and ot (overtime) hours and the sum of each row is populated in the total box but at the bottom I have to manually total the column values.
What I would like to do is eliminate the amount of data that has to be input into the form by having javascript calculate the start time and stop time and add the values to the reg, ot and total fields then sum up those columns at the bottom for the grandtotals.
The reason I want to do it like this is that this form is converted into a phone app and the less that is needed to input the fewer mistakes made.
I'm pretty new to this so I'm sure what I have is either incorrect (although it works), or there is a better way to accomplish it with less coding.
Any direction, input or help is greatly appreciated.
function sum() {
var txtFirstNumberValue = document.getElementById('reghours').value;
var txtSecondNumberValue = document.getElementById('othours').value;
var result = parseInt(txtFirstNumberValue) + parseInt(txtSecondNumberValue);
if (!isNaN(result)) {
document.getElementById('totalhours').value = result;
}
}
function sum2() {
var txtFirstNumberValue = document.getElementById('reghours2').value;
var txtSecondNumberValue = document.getElementById('othours2').value;
var result = parseInt(txtFirstNumberValue) + parseInt(txtSecondNumberValue);
if (!isNaN(result)) {
document.getElementById('totalhours2').value = result;
}
}
function sum3() {
var txtFirstNumberValue = document.getElementById('reghours3').value;
var txtSecondNumberValue = document.getElementById('othours3').value;
var result = parseInt(txtFirstNumberValue) + parseInt(txtSecondNumberValue);
if (!isNaN(result)) {
document.getElementById('totalhours3').value = result;
}
}
function sum4() {
var txtFirstNumberValue = document.getElementById('reghours4').value;
var txtSecondNumberValue = document.getElementById('othours4').value;
var result = parseInt(txtFirstNumberValue) + parseInt(txtSecondNumberValue);
if (!isNaN(result)) {
document.getElementById('totalhours4').value = result;
}
}
function sum5() {
var txtFirstNumberValue = document.getElementById('reghours5').value;
var txtSecondNumberValue = document.getElementById('othours5').value;
var result = parseInt(txtFirstNumberValue) + parseInt(txtSecondNumberValue);
if (!isNaN(result)) {
document.getElementById('totalhours5').value = result;
}
}
</script>
<script>
$(function() {
$('#BasicExample').timepicker();
});
$(function() {
$('#BasicExample2').timepicker();
});
$(function() {
$('#BasicExample3').timepicker();
});
$(function() {
$('#BasicExample4').timepicker();
});
$(function() {
$('#BasicExample5').timepicker();
});
$(function() {
$('#BasicExample6').timepicker();
});
$(function() {
$('#BasicExample7').timepicker();
});
$(function() {
$('#BasicExample8').timepicker();
});
$(function() {
$('#BasicExample9').timepicker();
});
$(function() {
$('#BasicExample10').timepicker();
});
.ui-timepicker-wrapper {
overflow-y: auto;
height: 150px;
width: 6.5em;
background: #fff;
border: 1px solid #ddd;
-webkit-box-shadow:0 5px 10px rgba(0,0,0,0.2);
-moz-box-shadow:0 5px 10px rgba(0,0,0,0.2);
box-shadow:0 5px 10px rgba(0,0,0,0.2);
outline: none;
z-index: 10001;
margin: 0;
}
.ui-timepicker-wrapper.ui-timepicker-with-duration {
width: 13em;
}
.ui-timepicker-wrapper.ui-timepicker-with-duration.ui-timepicker-step-30,
.ui-timepicker-wrapper.ui-timepicker-with-duration.ui-timepicker-step-60 {
width: 11em;
}
.ui-timepicker-list {
margin: 0;
padding: 0;
list-style: none;
}
.ui-timepicker-duration {
margin-left: 5px; color: #888;
}
.ui-timepicker-list:hover .ui-timepicker-duration {
color: #888;
}
.ui-timepicker-list li {
padding: 3px 0 3px 5px;
cursor: pointer;
white-space: nowrap;
color: #000;
list-style: none;
margin: 0;
}
.ui-timepicker-list:hover .ui-timepicker-selected {
background: #fff; color: #000;
}
li.ui-timepicker-selected,
.ui-timepicker-list li:hover,
.ui-timepicker-list .ui-timepicker-selected:hover {
background: #1980EC; color: #fff;
}
li.ui-timepicker-selected .ui-timepicker-duration,
.ui-timepicker-list li:hover .ui-timepicker-duration {
color: #ccc;
}
.ui-timepicker-list li.ui-timepicker-disabled,
.ui-timepicker-list li.ui-timepicker-disabled:hover,
.ui-timepicker-list li.ui-timepicker-selected.ui-timepicker-disabled {
color: #888;
cursor: default;
}
.ui-timepicker-list li.ui-timepicker-disabled:hover,
.ui-timepicker-list li.ui-timepicker-selected.ui-timepicker-disabled {
background: #f2f2f2;
}
.auto-style1 {
text-align: right;
}
body {
font-family: sans-serif;
}
#summation {
font-size: 16px;
font-weight: bold;
color:#174C68;
}
.txt {
background-color: #FEFFB0;
font-weight: bold;
text-align: center;
}
}
<script src="https://ajax.googleapis.com/ajax/libs/jquery/1.7.1/jquery.min.js"></script>
<script src="http://jemtech.us/scripts/jquery.timepicker.min.js"></script>
<script src="http://jemtech.us/scripts/jquery.timepicker.js"></script>
<body>
<form action="process_form.php" method="post">
<table align="center" style="width: 498px">
<td class="auto-style1"> </td>
<td class="auto-style1"> </td>
<td class="auto-style1" style="width: 127px"> </td>
</table>
<table align="center" class="auto-style6" style="width: 857px">
<th class="auto-style5" style="width: 47px">Start</th>
<th class="auto-style5" style="width: 47px">Stop</th>
<th class="auto-style5" style="width: 43px">Reg</th>
<th class="auto-style5" style="width: 45px">OT</th>
<th class="auto-style5" style="width: 51px">Total</th>
<th class="auto-style5"></th>
<tr>
<td style="height: 26px; width: 47px;">
<input id="BasicExample" type="text" class="time" style="width: 85px" />
</td>
<td style="height: 26px; width: 47px;">
<input id="BasicExample2" type="text" class="time" style="width: 85px" />
</td>
<td style="height: 26px; width: 43px;">
<input type="text" class="txt" name="RegularHours" id="reghours" onkeyup="sum()" style="width: 45px" />
</td>
<td style="height: 26px; width: 45px;">
<input type="text" class="txt" name="OTHours" id="othours" value="0" onkeyup="sum()" style="width: 45px" />
</td>
<td style="height: 26px; width: 51px;">
<input type="text" class="txt" name="TotalHours" id="totalhours" style="width: 50px" readonly/>
</td>
<td style="height: 26px">
</td>
</tr>
<tr>
<td style="height: 26px; width: 47px;">
<input id="BasicExample3" type="text" class="time" style="width: 85px" />
</td>
<td style="height: 26px; width: 47px;">
<input id="BasicExample4" type="text" class="time" style="width: 85px" />
</td>
<td style="height: 26px; width: 43px;">
<input type="text" class="txt" name="RegularHours2" id="reghours2" onkeyup="sum2()" style="width: 45px" />
</td>
<td style="height: 26px; width: 45px;">
<input type="text" class="txt" name="OTTotal2" id="othours2" value="0" onkeyup="sum2()" style="width: 45px" />
</td>
<td style="height: 26px; width: 51px;">
<input type="text" class="txt" name="TotalHours2" id="totalhours2" style="width: 50px" readonly/>
</td>
<td style="height: 26px">
</td>
</tr>
<tr>
<td style="height: 26px; width: 47px;">
<input id="BasicExample5" type="text" class="time" style="width: 85px" />
</td>
<td style="height: 26px; width: 47px;">
<input id="BasicExample6" type="text" class="time" style="width: 85px" />
</td>
<td style="height: 17px; width: 43px;">
<input type="text" class="txt" class="txt" name="RegularHours3" id="reghours3" onkeyup="sum3()" style="width: 45px" />
</td>
<td style="height: 17px; width: 45px;">
<input type="text" class="txt" class="txt" name="OTHours3" id="othours3" value="0" onkeyup="sum3()" style="width: 45px" />
</td>
<td style="height: 17px; width: 51px;">
<input type="text" class="txt" class="txt" name="TotalHours3" id="totalhours3" style="width: 50px" readonly/>
</td>
<td style="height: 17px">
</td>
</tr>
<tr>
<td style="height: 26px; width: 47px;">
<input id="BasicExample7" type="text" class="time" style="width: 85px" />
</td>
<td style="height: 26px; width: 47px;">
<input id="BasicExample8" type="text" class="time" style="width: 85px" />
</td>
<td style="width: 43px">
<input type="text" class="txt" name="RegularHours4" id="reghours4" onkeyup="sum4()" style="width: 45px" />
</td>
<td style="width: 45px">
<input type="text" class="txt" name="OTHours4" id="othours4" value="0" onkeyup="sum4()" style="width: 45px" />
</td>
<td style="width: 51px">
<input type="text" class="txt" name="TotalHours4" id="totalhours4" style="width: 50px" readonly/>
</td>
<td>
</td>
</tr>
<tr>
<td style="height: 26px; width: 47px;">
<input id="BasicExample9" type="text" class="time" style="width: 85px" />
</td>
<td style="height: 26px; width: 47px;">
<input id="BasicExample10" type="text" class="time" style="width: 85px" />
</td>
<td style="width: 43px">
<input type="text" class="txt" name="RegularHours5" id="reghours5" onkeyup="sum5()" style="width: 45px" />
</td>
<td style="width: 45px">
<input type="text" class="txt" name="OTHours5" id="othours5" value="0" onkeyup="sum5()" style="width: 45px" />
</td>
<td style="width: 51px">
<input type="text" class="txt" name="TotalHours5" id="totalhours5" style="width: 50px" readonly/>
</td>
<td>
</td>
</tr>
</table>
<div class="auto-style1" style="width: 640px; height: 26px">
<td><strong>Total Hours</strong>
</td>
<td>
<input type="text" class="txt" name="RegTotal" id="total" style="width: 45px" readonly />
</td>
<td>
<input type="text" class="txt" name="OTTotal" id="total" style="width: 45px" readonly/>
</td>
<td style="width: 45px">
<tr id="summation">
<td style="width: 50px">
<input type="text" class="txt" name="GrandTotal" id="grandtotal" style="width: 50px" readonly/>
</td>
<td style="height: 23px"></td>
</tr>
</td>
</div>
<div style="height: 35px"></div>
<hr />
<br/>
<input type="submit" name="submit" value="Submit" />
</form>
</body>
Please consider using a jQuery TimePicker Plugin as mentioned in https://www.sitepoint.com/10-jquery-time-picker-plugins/ together with https://momentjs.com/ for calculations.
As others have mentioned a date picker will make this easier for both you and your users. Either way, you will need to parse your inputs to get date objects
// With date picker
var startDate = new Date(startPicker.value);
or
// With current select inputs
// Get AM/PM hours - hourSelect should be the select element for hours
var startHrs = periodSelect.value === 'PM'
? parseInt(hourSelect.options[hourSelect.selectedIndex].value, 10)
: parseInt(hourSelect.options[hourSelect.selectedIndex].value, 10) + 12;
// No date provided so use dummy date (1970-1-1)
var startDate = new Date(
1970,
1,
1,
startHrs,
minuteSelect.options[minuteSelect.selectedIndex].value; // minuteSelect should be the select element for minutes
);
Then calculate the difference between your start and end dates. As mentioned you can use moment.js for this but the regular date object should be sufficient.
function getDifference(startDate, endDate) {
return new Date(endDate.getTime() - startDate.getTime());
}
Now you can use difference.getUTCHours() and difference.getUTCMinutes to get the total time worked. It should be trivial to get regular and overtime from the total. Remember to check that the start time is before the end.
... or there is a better way to accomplish it with less coding.
The essence of the question seems to be about how to keep the code DRY, not about whether or not to use a date-picker (though that is also an important decision).
The golden rules in spreadsheet-like apps like this with repeated rows are :
use classes for elements in the repeated rows
use ids only for non-repeating element
Here's a general framework :
jQuery(function($) {
var overtimeAfter = 8.0; // hours per day
// *** utility Constructor ***
function Hours(std, ot) {
return {'std':std, 'ot':ot};
}
Hours.prototype.add = function(otherHours) {
return new Hours(this.std+otherHours.std, this.ot+otherHours.ot);
}
// *** utility functions ***
function getTime(input) {
// Here, do whatever is necessary to convert input values to some standard abstraction:
// for example, 24H string or js Date() object.
return Number(input.val()); // simplest case
}
function timeDiffernce(t1, t2) {
// Here do whatever is necessary to calculate the time difference
// between t2 and t1, in whatever abstraction was returned by getTime().
// For example:
var t = t2 - t1; // simplest case
return (t < 0) ? 24 + t : t; // allow for t1...t2 to span midnight
}
// *** core functions ***
function calcDayHours(tr) {
// here is where you benefit from classes within the table row
var time1 = getTime($('.time1', tr));
var time2 = getTime($('.time2', tr));
var hours = timeDiffernce(time1, time2);
var std = Math.min(hours, overtimeAfter);
var ot = Math.max(0, hours - overtimeAfter);
var total = std + ot;
$('.reghours', tr).val(std);
$('.othours', tr).val(ot);
$(".totalhours", tr).val(total);
return new Hours(std, ot);
}
function calcWeekHours(hours) {
var weekHours = hours.reduce(function(week, day) {
return week.add(day);
}, new Hours(0, 0));
// these elements are unique, therefore identified by id.
$("#regTotal").val(weekHours.std);
$("#otTotal").val(weekHours.ot);
$("#grandTotal").val(weekHours.std + weekHours.ot);
return weekHours;
}
// *** master function ***
function sum() {
// Assume a table or tbody with id="timesheet"
var dayHours = $("#timesheet tr").get().map(calcDayHours);
var weekHours = calcWeekHours(dayHours);
// if you want wage calculations, then pass `weekHours` to a `calcWages()` function.
// var wages = calcWages(weekHours);
}
// Then attach `sum` as the handler for all kinds of keyup/tap/click/focus/blur events.
});
As I say, that's just a framework. There are still decisions to make, eg :
what you write in getTime() will depend on the expected date/time input format (text vs date-picker ...)
what you write in timeDiffernce() will depend on what you decide to return from getTime() (Number vs Date ...).
which ui event(s) should trigger sum().
how to specify the overtime threshold overtimeAfter - hardcoding as above will get you started.
how to accommodate overtime thresholds on a "per day", "per week" or "per month" basis - wage systems vary.
So Im having trouble with my form. There are numurous validation techniques set up.
Two of my most obvious problems are an alert that pops upen at the start of the program but should only pop up if an onblur() is activated and my update() function returns a false value.
And aswell, my regular Expressions insist on providing me with false condition when I test them against my strings.
The finished form should validate various information and update values placed in the expenses inputs.
Really stuck on this...
window.onload = initPage;
/*initPage()
Initializes the contents of the Web page */
function initPage() {
//declare array variable dataFields points to input elements from the expenseEntry class
var dataFields = new Array();
var allElems = document.getElementsByTagName("*");
for( var i = 0; i < allElems.length; i ++) {
if(allElems[i].className == "expenseEntry") dataFields.push(allElems[i]);
}
//add onblur event that runs update() function whenever focus leaves a datafield.
for(var i = 0; i < dataFields.length; i++) {
dataFields[i].onblur = update();
}
//event handler that runs validateForm() upon submitting the form.
document.forms[0].onsubmit = validateForm;
}
/* testLength()
Tests a field for its length. */
function testLength(field) {
if (field.value.length == 0) {
// Change the background color to white or yellow depending on the lenght.
field.style.backgroundColor = "yellow";
return false;
}
else field.style.backgroundColor = "white";
return true;
}
/* testPattern()
Tests a field for its pattern. */
function testPattern(field, regx) {
if (regx.test(field)) {
field.style.backgroundColor = "white";
field.style.color = "black";
return true;
}
else field.style.backgroundColor = "yellow";
field.style.color = "red";
return false;
}
/* validateForm()
Validates a Web form */
function validateForm() {
var isValid = true;
//testLength function with lname field also for fname, address, and summary to make sure an entry has been made.
if (testLength(document.forms[0].lname) == false) {
isValid = false;}
if (testLength(document.forms[0].fname) == false) {
isValid = false;}
if (testLength(document.forms[0].address) == false) {
isValid = false;}
if (testLength(document.forms[0].summary) == false) {
isValid = false;}
//must match ACT followed by six digits
if (testPattern(document.forms[0].account,/^ACT\d{6}$/) == false)
{isValid = false;}
//dept field. regx should match DEPT followed by three digits
if (testPattern(document.forms[0].department.value,/^DEPT\d{3}$/) == false)
{isValid = false;}
//Project field with regx should match PROJ followed by five digits
if (testPattern(document.forms[0].project,/^PROJ\d{5}$/) == false)
{isValid = false;}
//call testPattern function to test SSN. match 9 digits or text string
if (testPattern(document.forms[0].ssn,/^\d{3}-\d{2}-\d{4}$/) == false)
{isValid = false;}
if (isValid == false)
{alert("Please fill out all required fields in the proper format.");}
return isValid;
}
/* calcRow
Calculates the costs within one row of the travel report */
function calcRow(row) {
var travel = parseFloat(document.forms[0].elements["travel"+row].value);
var lodge = parseFloat(document.forms[0].elements["lodge"+row].value);
var meal = parseFloat(document.forms[0].elements["meal"+row].value);
return travel+lodge+meal;
}
/* calcTotal()
Calculates the total cost of the travel */
function calcTotal() {
//create a variable totalEXP
var totalExp = 0;
//create a for loop that runs 1 t0 4
for (var i = 1; i <= 4; i++)
// increase the value of totalExp by value returned for calcRow
{ totalExp += calcRow(i);}
return totalExp;
}
/* upDate()
Updates the total travel cost */
function update() {
//create a variable numRegExp
var numRegExp = /^\d*(\.\d{0,2})?$/;
// Test weather the currently selected object matches the numRegExp pattern
if (numRegExp.test(this.value)){
// Display the value of the current object to 2 decimal places.
parseInt(this.value).toFixed(2);
//insert a for loop that runs 1 to 4 for all the expense rows in the form
for (var i = 1; i < 4; i++) {
//Set the value of sub[i] field to the value returned by calcRow()
document.forms[0].elements["sub" + i].value = calcRow(i).toFixed(2);
//set the value of the total field equal to the value returned by the calTotal() function
document.forms[0].total.value = calcTotal().toFixed(2);
}
}
//if the condition is not met display alert and change value.
else if (numRegExp.test(this.value) == false) {
alert("Invalid currency value");
(this.value = "0.00");
this.focus();
}
}
body {background: white url(back.jpg) repeat-y scroll 0px 0px}
#links {position: absolute; top: 10px; left: 0px}
#main {border: 1px solid black; width: 640px; padding: 5px;
background-color: white; margin-left: 100px; margin-top: 0px}
span {color: red; font-family: Arial, Helvetica, sans-serif; font-size: 9pt}
table {font-size: 8pt; width: 630px; margin-top: 5px; margin-bottom: 0px}
th {background-color: rgb(153,204,255); text-align: left; font-weight: normal;
font-family: Arial, Helvetica, sans-serif}
#reporttitle {background-color: white; text-align: center; font-family: Arial, Helvetica, sans-serif;
font-size: 18pt; color: rgb(153,204,255); font-weight: bold}
input {width: 100%; font-size: 8pt}
select {width: 100%; font-size: 8pt}
#lname, #fname {width: 150px}
#account, #department, #project {width: 150px}
#traveltable th {text-align: center}
#subhead {width: 100px}
#travelexphead, #lodgeexphead, #mealexphead {width: 80px}
#date1, #date2, #date3, #date4 {text-align: center}
#travel1, #travel2, #travel3, #travel4 {text-align: right}
#lodge1, #lodge2, #lodge3, #lodge4 {text-align: right}
#meal1, #meal2, #meal3, #meal4 {text-align: right}
#sub1, #sub2, #sub3, #sub4,#total {text-align: right}
#traveltable #totalhead {text-align: right}
textarea {height: 100px; width: 100%}
#main #psub {text-align: center}
#main p input {width: 190px; background-color: rgb(153,204,255); color: black;
letter-spacing: 5}
<?xml version="1.0" encoding="UTF-8" ?>
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Strict//EN"
"http://www.w3.org/TR/xhtml1/DTD/xhtml1-strict.dtd">
<html xmlns="http://www.w3.org/1999/xhtml">
<head>
<!--
New Perspectives on JavaScript, 2nd Edition
Tutorial 5
Case Problem 2
Expense Report Form
Author: Gavin Macken
Date: 8 March `15
Filename: exp.htm
Supporting files: back.jpg, exp.css, links.jpg, logo.jpg, report.js
-->
<title>Expense Report</title>
<link href="exp.css" rel="stylesheet" type="text/css" />
<script src = "report.js" type = "text/javascript"></script>
</head>
<body>
<form id="expform" method="post" action="done.htm">
<div id="links"><img src="links.jpg" alt="" /></div>
<div id="main">
<p><img src="logo.jpg" alt="DeLong Enterprises" /></p>
<table cellspacing="2">
<tr>
<th colspan="5" id="reporttitle">Travel Expense Report</th>
</tr>
<tr>
<th>Name (Last)<span>*</span></th>
<th>(First)<span>*</span></th>
<th>(Initial)</th>
<th>Account<span>*</span></th>
<td><input name="account" id="account" /></td>
</tr>
<tr>
<td><input name="lname" id="lname"/></td>
<td><input name="fname" id="fname"/></td>
<td><input name="init" id="init"/></td>
<th>Department<span>*</span></th>
<td><input name="department" id="department" /></td>
</tr>
<tr>
<th>Social Security Number<span>*</span></th>
<td colspan="2"><input name="ssn" id="ssn" /></td>
<th>Project<span>*</span></th>
<td><input name="project" id="project" /></td>
</tr>
</table>
<table cellspacing="2">
<tr>
<th>Send Check to:<span>*</span></th>
<th>Trip Summary<span>*</span></th>
</tr>
<tr>
<td>
<textarea id="address" name="address" rows="" cols=""></textarea>
</td>
<td>
<textarea id="summary" name="summary" rows="" cols=""></textarea>
</td>
</tr>
</table>
<table id="traveltable" cellspacing="2">
<tr>
<th id="datehead">Travel Date</th>
<th id="travelexphead">Travel Cost</th>
<th id="traveltypehead">Type</th>
<th id="lodgeexphead">Lodging</th>
<th id="mealexphead">Meals</th>
<th id="subhead">Total</th>
</tr>
<tr>
<td><input name="date1" id="date1" /></td>
<td><input name="travel1" id="travel1" value="0.00" class="expenseEntry" /></td>
<td><select name="traveltype1" id="traveltype1">
<option>air</option>
<option>auto</option>
<option>taxi</option>
<option>train</option>
</select>
</td>
<td><input name="lodge1" id="lodge1" value="0.00" class="expenseEntry" /></td>
<td><input name="meal1" id="meal1" value="0.00" class="expenseEntry" /></td>
<td><input name="sub1" id="sub1" value="0.00" readonly="readonly" /></td>
</tr>
<tr>
<td><input name="date2" id="date2" /></td>
<td><input name="travel2" id="travel2" value="0.00" class="expenseEntry" /></td>
<td><select name="traveltype2" id="traveltype2">
<option>air</option>
<option>auto</option>
<option>taxi</option>
<option>train</option>
</select>
</td>
<td><input name="lodge2" id="lodge2" value="0.00" class="expenseEntry" /></td>
<td><input name="meal2" id="meal2" value="0.00" class="expenseEntry" /></td>
<td><input name="sub2" id="sub2" value="0.00" readonly="readonly" /></td>
</tr>
<tr>
<td><input name="date3" id="date3" /></td>
<td><input name="travel3" id="travel3" value="0.00" class="expenseEntry" /></td>
<td><select name="traveltype3" id="traveltype3">
<option>air</option>
<option>auto</option>
<option>taxi</option>
<option>train</option>
</select>
</td>
<td><input name="lodge3" id="lodge3" value="0.00" class="expenseEntry" /></td>
<td><input name="meal3" id="meal3" value="0.00" class="expenseEntry" /></td>
<td><input name="sub3" id="sub3" value="0.00" readonly="readonly" /></td>
</tr>
<tr>
<td><input name="date4" id="date4" /></td>
<td><input name="travel4" id="travel4" value="0.00" class="expenseEntry" /></td>
<td><select name="traveltype4" id="traveltype4">
<option>air</option>
<option>auto</option>
<option>taxi</option>
<option>train</option>
</select>
</td>
<td><input name="lodge4" id="lodge4" value="0.00" class="expenseEntry" /></td>
<td><input name="meal4" id="meal4" value="0.00" class="expenseEntry" /></td>
<td><input name="sub4" id="sub4" value="0.00" readonly="readonly" /></td>
</tr>
<tr>
<th colspan="5" id="totalhead">TOTAL</th>
<td><input id="total" name="total" readonly="readonly" value="0.00" /></td>
</tr>
<tr>
<td colspan="6"><span>* - Indicates a required field</span></td>
</tr>
</table>
<p id="psub">
<input type="submit" value="Submit Report" />
</p>
</div>
</form>
</body>
</html>
You're testing the DOM element against the regexp, which doesn't make sense. The argument to regx.test() must be a string. You need to use the value of the field:
if (regx.test(field.value)) {
You're setting the onblur property wrong. It should be set to the update function, but you're calling the function at that time. It should be:
dataFields[i].onblur = update;
And you were using the .value property when you called testPattern for the department field. But testPattern expects the argument to be the element, not the value. It should be:
if (testPattern(document.forms[0].department, /^DEPT\d{3}$/) == false)
window.onload = initPage;
/*initPage()
Initializes the contents of the Web page */
function initPage() {
//declare array variable dataFields points to input elements from the expenseEntry class
var dataFields = new Array();
var allElems = document.getElementsByTagName("*");
for (var i = 0; i < allElems.length; i++) {
if (allElems[i].className == "expenseEntry") dataFields.push(allElems[i]);
}
//add onblur event that runs update() function whenever focus leaves a datafield.
for (var i = 0; i < dataFields.length; i++) {
dataFields[i].onblur = update;
}
//event handler that runs validateForm() upon submitting the form.
document.forms[0].onsubmit = validateForm;
}
/* testLength()
Tests a field for its length. */
function testLength(field) {
if (field.value.length == 0) {
// Change the background color to white or yellow depending on the lenght.
field.style.backgroundColor = "yellow";
return false;
} else field.style.backgroundColor = "white";
return true;
}
/* testPattern()
Tests a field for its pattern. */
function testPattern(field, regx) {
if (regx.test(field.value)) {
field.style.backgroundColor = "white";
field.style.color = "black";
return true;
} else field.style.backgroundColor = "yellow";
field.style.color = "red";
return false;
}
/* validateForm()
Validates a Web form */
function validateForm() {
var isValid = true;
//testLength function with lname field also for fname, address, and summary to make sure an entry has been made.
if (testLength(document.forms[0].lname) == false) {
isValid = false;
}
if (testLength(document.forms[0].fname) == false) {
isValid = false;
}
if (testLength(document.forms[0].address) == false) {
isValid = false;
}
if (testLength(document.forms[0].summary) == false) {
isValid = false;
}
//must match ACT followed by six digits
if (testPattern(document.forms[0].account, /^ACT\d{6}$/) == false)
{
isValid = false;
}
//dept field. regx should match DEPT followed by three digits
if (testPattern(document.forms[0].department, /^DEPT\d{3}$/) == false)
{
isValid = false;
}
//Project field with regx should match PROJ followed by five digits
if (testPattern(document.forms[0].project, /^PROJ\d{5}$/) == false)
{
isValid = false;
}
//call testPattern function to test SSN. match 9 digits or text string
if (testPattern(document.forms[0].ssn, /^\d{3}-\d{2}-\d{4}$/) == false) {
isValid = false;
}
if (isValid == false)
{
alert("Please fill out all required fields in the proper format.");
}
return isValid;
}
/* calcRow
Calculates the costs within one row of the travel report */
function calcRow(row) {
var travel = parseFloat(document.forms[0].elements["travel" + row].value);
var lodge = parseFloat(document.forms[0].elements["lodge" + row].value);
var meal = parseFloat(document.forms[0].elements["meal" + row].value);
return travel + lodge + meal;
}
/* calcTotal()
Calculates the total cost of the travel */
function calcTotal() {
//create a variable totalEXP
var totalExp = 0;
//create a for loop that runs 1 t0 4
for (var i = 1; i <= 4; i++)
// increase the value of totalExp by value returned for calcRow
{
totalExp += calcRow(i);
}
return totalExp;
}
/* upDate()
Updates the total travel cost */
function update() {
//create a variable numRegExp
var numRegExp = /^\d*(\.\d{0,2})?$/;
// Test weather the currently selected object matches the numRegExp pattern
if (numRegExp.test(this.value)) {
// Display the value of the current object to 2 decimal places.
parseInt(this.value).toFixed(2);
//insert a for loop that runs 1 to 4 for all the expense rows in the form
for (var i = 1; i < 4; i++) {
//Set the value of sub[i] field to the value returned by calcRow()
document.forms[0].elements["sub" + i].value = calcRow(i).toFixed(2);
//set the value of the total field equal to the value returned by the calTotal() function
document.forms[0].total.value = calcTotal().toFixed(2);
}
}
//if the condition is not met display alert and change value.
else if (numRegExp.test(this.value) == false) {
alert("Invalid currency value");
(this.value = "0.00");
this.focus();
}
}
body {
background: white url(back.jpg) repeat-y scroll 0px 0px
}
#links {
position: absolute;
top: 10px;
left: 0px
}
#main {
border: 1px solid black;
width: 640px;
padding: 5px;
background-color: white;
margin-left: 100px;
margin-top: 0px
}
span {
color: red;
font-family: Arial, Helvetica, sans-serif;
font-size: 9pt
}
table {
font-size: 8pt;
width: 630px;
margin-top: 5px;
margin-bottom: 0px
}
th {
background-color: rgb(153, 204, 255);
text-align: left;
font-weight: normal;
font-family: Arial, Helvetica, sans-serif
}
#reporttitle {
background-color: white;
text-align: center;
font-family: Arial, Helvetica, sans-serif;
font-size: 18pt;
color: rgb(153, 204, 255);
font-weight: bold
}
input {
width: 100%;
font-size: 8pt
}
select {
width: 100%;
font-size: 8pt
}
#lname,
#fname {
width: 150px
}
#account,
#department,
#project {
width: 150px
}
#traveltable th {
text-align: center
}
#subhead {
width: 100px
}
#travelexphead,
#lodgeexphead,
#mealexphead {
width: 80px
}
#date1,
#date2,
#date3,
#date4 {
text-align: center
}
#travel1,
#travel2,
#travel3,
#travel4 {
text-align: right
}
#lodge1,
#lodge2,
#lodge3,
#lodge4 {
text-align: right
}
#meal1,
#meal2,
#meal3,
#meal4 {
text-align: right
}
#sub1,
#sub2,
#sub3,
#sub4,
#total {
text-align: right
}
#traveltable #totalhead {
text-align: right
}
textarea {
height: 100px;
width: 100%
}
#main #psub {
text-align: center
}
#main p input {
width: 190px;
background-color: rgb(153, 204, 255);
color: black;
letter-spacing: 5
}
<?xml version="1.0" encoding="UTF-8" ?>
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Strict//EN"
"http://www.w3.org/TR/xhtml1/DTD/xhtml1-strict.dtd">
<html xmlns="http://www.w3.org/1999/xhtml">
<head>
<!--
New Perspectives on JavaScript, 2nd Edition
Tutorial 5
Case Problem 2
Expense Report Form
Author: Gavin Macken
Date: 8 March `15
Filename: exp.htm
Supporting files: back.jpg, exp.css, links.jpg, logo.jpg, report.js
-->
<title>Expense Report</title>
<link href="exp.css" rel="stylesheet" type="text/css" />
<script src="report.js" type="text/javascript"></script>
</head>
<body>
<form id="expform" method="post" action="done.htm">
<div id="links">
<img src="links.jpg" alt="" />
</div>
<div id="main">
<p>
<img src="logo.jpg" alt="DeLong Enterprises" />
</p>
<table cellspacing="2">
<tr>
<th colspan="5" id="reporttitle">Travel Expense Report</th>
</tr>
<tr>
<th>Name (Last)<span>*</span>
</th>
<th>(First)<span>*</span>
</th>
<th>(Initial)</th>
<th>Account<span>*</span>
</th>
<td>
<input name="account" id="account" />
</td>
</tr>
<tr>
<td>
<input name="lname" id="lname" />
</td>
<td>
<input name="fname" id="fname" />
</td>
<td>
<input name="init" id="init" />
</td>
<th>Department<span>*</span>
</th>
<td>
<input name="department" id="department" />
</td>
</tr>
<tr>
<th>Social Security Number<span>*</span>
</th>
<td colspan="2">
<input name="ssn" id="ssn" />
</td>
<th>Project<span>*</span>
</th>
<td>
<input name="project" id="project" />
</td>
</tr>
</table>
<table cellspacing="2">
<tr>
<th>Send Check to:<span>*</span>
</th>
<th>Trip Summary<span>*</span>
</th>
</tr>
<tr>
<td>
<textarea id="address" name="address" rows="" cols=""></textarea>
</td>
<td>
<textarea id="summary" name="summary" rows="" cols=""></textarea>
</td>
</tr>
</table>
<table id="traveltable" cellspacing="2">
<tr>
<th id="datehead">Travel Date</th>
<th id="travelexphead">Travel Cost</th>
<th id="traveltypehead">Type</th>
<th id="lodgeexphead">Lodging</th>
<th id="mealexphead">Meals</th>
<th id="subhead">Total</th>
</tr>
<tr>
<td>
<input name="date1" id="date1" />
</td>
<td>
<input name="travel1" id="travel1" value="0.00" class="expenseEntry" />
</td>
<td>
<select name="traveltype1" id="traveltype1">
<option>air</option>
<option>auto</option>
<option>taxi</option>
<option>train</option>
</select>
</td>
<td>
<input name="lodge1" id="lodge1" value="0.00" class="expenseEntry" />
</td>
<td>
<input name="meal1" id="meal1" value="0.00" class="expenseEntry" />
</td>
<td>
<input name="sub1" id="sub1" value="0.00" readonly="readonly" />
</td>
</tr>
<tr>
<td>
<input name="date2" id="date2" />
</td>
<td>
<input name="travel2" id="travel2" value="0.00" class="expenseEntry" />
</td>
<td>
<select name="traveltype2" id="traveltype2">
<option>air</option>
<option>auto</option>
<option>taxi</option>
<option>train</option>
</select>
</td>
<td>
<input name="lodge2" id="lodge2" value="0.00" class="expenseEntry" />
</td>
<td>
<input name="meal2" id="meal2" value="0.00" class="expenseEntry" />
</td>
<td>
<input name="sub2" id="sub2" value="0.00" readonly="readonly" />
</td>
</tr>
<tr>
<td>
<input name="date3" id="date3" />
</td>
<td>
<input name="travel3" id="travel3" value="0.00" class="expenseEntry" />
</td>
<td>
<select name="traveltype3" id="traveltype3">
<option>air</option>
<option>auto</option>
<option>taxi</option>
<option>train</option>
</select>
</td>
<td>
<input name="lodge3" id="lodge3" value="0.00" class="expenseEntry" />
</td>
<td>
<input name="meal3" id="meal3" value="0.00" class="expenseEntry" />
</td>
<td>
<input name="sub3" id="sub3" value="0.00" readonly="readonly" />
</td>
</tr>
<tr>
<td>
<input name="date4" id="date4" />
</td>
<td>
<input name="travel4" id="travel4" value="0.00" class="expenseEntry" />
</td>
<td>
<select name="traveltype4" id="traveltype4">
<option>air</option>
<option>auto</option>
<option>taxi</option>
<option>train</option>
</select>
</td>
<td>
<input name="lodge4" id="lodge4" value="0.00" class="expenseEntry" />
</td>
<td>
<input name="meal4" id="meal4" value="0.00" class="expenseEntry" />
</td>
<td>
<input name="sub4" id="sub4" value="0.00" readonly="readonly" />
</td>
</tr>
<tr>
<th colspan="5" id="totalhead">TOTAL</th>
<td>
<input id="total" name="total" readonly="readonly" value="0.00" />
</td>
</tr>
<tr>
<td colspan="6"><span>* - Indicates a required field</span>
</td>
</tr>
</table>
<p id="psub">
<input type="submit" value="Submit Report" />
</p>
</div>
</form>
</body>
</html>
<ul class="liste_couleur_qty">
<li style="margin-bottom: 20px;">
<dl>
<table width="200" border="0">
<tbody><tr>
<td width="50%">
<span style="display: block; font-size: 13px; line-height: 16px; margin-bottom: 2px;margin-right: 0px;margin-left: 20px;">Noir</span>
</td>
<td width="50%"><div class="add-to-cart">
<label for="qty-2195">qty :</label>
<input type="text" class="input-text qty calcul_qty_product" title="Qté" value="0" autocomplete="off" maxlength="5" data-product_color="127" id="qty-2195" name="qty-2195" onblur="addToCartPlus(2195, 127, this);">
</div></td>
</tr>
</tbody></table>
</dl>
</li>
<li style="margin-bottom: 20px;">
<dl>
<table width="200" border="0">
<tbody><tr>
<td width="50%">
<span style="display: block; font-size: 13px; line-height: 16px; margin-bottom: 2px;margin-right: 0px;margin-left: 20px;">Blanc</span>
</td>
<td width="50%"><div class="add-to-cart">
<label for="qty-2196">qty :</label>
<input type="text" class="input-text qty calcul_qty_product" title="Qté" value="0" autocomplete="off" maxlength="5" id="qty-2196" name="qty-2196" onblur="addToCartPlus();">
</div></td>
</tr>
</tbody></table>
</dl>
</li>
<li style="margin-bottom: 20px;">
<dl>
<table width="200" border="0">
<tbody><tr>
<td width="50%">
<span style="display: block; font-size: 13px; line-height: 16px; margin-bottom: 2px;margin-right: 0px;margin-left: 20px;">Blanc</span>
</td>
<td width="50%"><div class="add-to-cart">
<label for="qty-2196">qty :</label>
<input type="text" class="input-text qty calcul_qty_product" title="Qté" value="0" autocomplete="off" maxlength="5" id="qty-2196" name="qty-2196" onblur="addToCartPlus();">
</div></td>
</tr>
</tbody></table>
</dl>
</li>
</ul>
<div id="qtyvalue"><div>
i want to do:
change the content of a div(qtyvalue) dynamically when the input value changes? if there are more input text vaule, add them together then shows the number in the div(qtyvalue). i using the following code.
input.onkeyup = function() {
var result = 0;
$('.liste_couleur_qty li input').each(function(){
result += parseInt(this.value, 10);
});
document.getElementById('qtyvalue').innerHTML = result.value;
}
but the code doesn't work, i don't know how to loop the input,if there are two or many input text box. thank you.
What you want is this:
$(document).ready(function() { //wrap in a document.ready event handler
$('input').on('keyup', function() { //bind using jQuery
var result = 0;
$('.liste_couleur_qty li input').each(function() {
result += parseInt(this.value, 10);
});
$('div#qtyvalue').text(result); //result.value doesn't exist, use result.
});
});
Here's a demo: http://jsfiddle.net/jeRdA/
UDPATE:
To allow for users changing the value of any of the inputs to ''(e.g., blank, or empty) or a non-numeric value, modify the line:
result += parseInt(this.value, 10);
to:
result += parseFloat(this.value, 10) || 0;
Updated fiddle: http://jsfiddle.net/jeRdA/3/
Try this:
var $inputs = $('.liste_couleur_qty li input');
$inputs.keyup(function() {
var result = 0;
$inputs.each(function(){
result += parseInt(this.value, 10);
});
$('#qtyvalue').html(result);
});
This would need to be in a document ready handler or in a script block after the elements in question (many people put their scripts at the end of the body).
In your code, input.onkeyup = ... wouldn't work because there is no variable input (it doesn't automatically pick up all input elements), and also using someElement.onkeyup = only lets you attach a handler to one element at a time. Use jQuery to bind the keyup handler instead. Also, to use the total at the end just use result, using result.value wouldn't work.