I'm trying to write code to detect if a ship has been hit or not. I have 3 ships on the board and each takes up 3 cells. Using js I placed the 3 ships on the board. And when I run the fire method, only the last two ships show they've been hit, but the first ship at location 00,01,02 doesn't indicate that it's been hit, even once. Where did I go wrong?
var view = {
showMessage: function(msg) {
var message = document.getElementById('message');
message.innerHTML = msg;
},
showHit: function(location) {
var cell = document.getElementById(location);
cell.setAttribute('class', 'hit');
},
showMiss: function(location) {
var cell = document.getElementById(location);
cell.setAttribute('class', 'miss');
}
}
var model = {
boardSize: 7,
numShips: 3,
shipsSunk: 3,
ships: [{
location: [00, 01, 02],
hits: ['', '', '']
},
{
location: [10, 11, 12],
hits: ['', '', '']
},
{
location: [20, 21, 22],
hits: ['', '', '']
}
],
fire: function(guess) {
for (var i = 0; i < this.numShips; i++) {
var ship = this.ships[i];
var index = ship.location.indexOf(guess);
if (index >= 0) {
ship.hits[index] = 'hit';
view.showHit(guess);
}
}
}
};
model.fire(10);
model.fire(11);
model.fire(12);
model.fire(20);
model.fire(21);
model.fire(22);
/*
model.fire(00);
model.fire(01);
model.fire(02); */
* {
margin: 0px;
padding: 0px;
}
body {
background-color: grey;
}
#message {
color: green;
font-size: 2em;
text-transform: uppercase;
font-family: sans-serif;
}
#board {
background: url('board.jpg') no-repeat;
width: 863px;
height: 1024px;
margin: auto;
position: relative;
}
table {
position: absolute;
left: 173px;
top: 98px;
}
td {
height: 94px;
width: 94px;
}
form input {
position: absolute;
right: 0px;
bottom: 0px;
background-color: green;
}
.hit {
background: url('ship.png') no-repeat center center;
}
.miss {
background: url('miss.png') no-repeat center center;
}
<div id='board'>
<div id='message'></div>
<table>
<tr>
<td id='00'></td>
<td id='01'></td>
<td id='02'></td>
<td id='03'></td>
<td id='04'></td>
<td id='05'></td>
<td id='06'></td>
</tr>
<tr>
<td id='10'></td>
<td id='11'></td>
<td id='12'></td>
<td id='13'></td>
<td id='14'></td>
<td id='15'></td>
<td id='16'></td>
</tr>
<tr>
<td id='20'></td>
<td id='21'></td>
<td id='22'></td>
<td id='23'></td>
<td id='24'></td>
<td id='25'></td>
<td id='26'></td>
</tr>
<tr>
<td id='30'></td>
<td id='31'></td>
<td id='32'></td>
<td id='33'></td>
<td id='34'></td>
<td id='35'></td>
<td id='36'></td>
</tr>
<tr>
<td id='40'></td>
<td id='41'></td>
<td id='42'></td>
<td id='43'></td>
<td id='44'></td>
<td id='45'></td>
<td id='46'></td>
</tr>
<tr>
<td id='50'></td>
<td id='51'></td>
<td id='52'></td>
<td id='53'></td>
<td id='54'></td>
<td id='55'></td>
<td id='56'></td>
</tr>
<tr>
<td id='60'></td>
<td id='61'></td>
<td id='62'></td>
<td id='63'></td>
<td id='64'></td>
<td id='65'></td>
<td id='66'></td>
</tr>
</table>
<form action='#' method='get'>
<input type='text' id='guessInput' placeholder='enter location: A0' />
<input type='button' name='submit' value='Fire!' name='fire' />
</form>
</div>
Your coordinates 00, 01, and 02 are interpreted as ints and are therefore resolved to 0, 1, and 2, because it is assumed that the leading zero is not needed for an int value. You can fix this by using strings to represent and compare the coordinates. Instead of model.fire(00), you will need model.fire("00"). Then to compare the input coordinates, you will need to compare guess.charAt(0) and guess.charAt(1) to determine if that coordinate is a hit.
Related
I have created two tables. The first table I name it atable and the second table I name it second . On the atable I have 3x3(3 columns x 3 rows) and on the second I have 1x9. I want to fill in the first table with numbers, I have created the begin() function so I will fill the table with random items,using a button named Start.Next, I have created a function named check(), it clicks on the first table(atable). Now, what I want to do is ,when I click on the table(atable) I want each of my clicking to transfer the number into the other table(named :second ).I have created the table second but I didn't find how to send the clicks from one table into the other table.
<!DOCTYPE html>
<html>
<head>
<script>
var timerid;
var secs = 30;
var randomNumber;
var mclics = 0;
var mcorrect = 0;
function begin() {
randomNumber = Math.round(Math.random() * 9);
var atable = document.getElementById("atable");
for (i = 0; i < atable.rows.length; i++) {
for(j = 0; j < atable.rows[i].cells.length; j++) {
var a = Math.ceil(Math.random()*100);
atable.rows[i].cells[j].innerHTML = a;
}
}
}
function check(trgt){
if(trgt.tagName=="TD"){
mclics++
trgt.onclick=false; //for not happen again click//
if((trgt.innerHTML%randomNumber)==0){
mcorrect++ //right clicks
trgt.style.backgroundColor = "green";
}
else{
trgt.style.backgroundColor = "red";
}
}
}
</script>
</head>
<body>
<input type="button" value="Start" onclick="begin()" style="width: 30%"><br>
<p id="anumber"></p>
<table id="atable" border="1" onclick="check(event.target)">
<tr>
<td style="width: 292px; height: 39px;"> </td>
<td style="width: 332px; height: 39px;"></td>
<td style="width: 260px; height: 39px;">
</tr>
<tr>
<td style="width: 292px; height: 46px;"></td>
<td style="width: 332px; height: 46px;"></td>
<td style="width: 260px; height: 46px;">
</tr>
<tr><td style="width: 292px; height: 172px;"></td>
<td style="width: 332px; height: 172px;"></td>
<td style="width: 260px; height: 172px;"> </tr>
</table>
<p >Remaining time: </p>
<p id="atimer"></p>
<table id="second" border="1" >
<tr><td style="width: 292px; height: 39px;"> </td> </tr>
<tr><td style="width: 332px; height: 39px;"></td></tr>
<tr><td style="width: 292px; height: 46px;"></td></tr>
<tr> <td style="width: 332px; height: 46px;"></td></tr>
<tr><td style="width: 332px; height: 39px;"></td></tr>
<tr><td style="width: 332px; height: 39px;"></td></tr>
<tr><td style="width: 332px; height: 39px;"></td></tr>
<tr><td style="width: 332px; height: 39px;"></td></tr>
<tr><td style="width: 332px; height: 39px;"></td></tr>
</table>
</body>
</html>
On the first table I added "EventListener". When you click on a number field, the function is called function getNumbers() which adds the number to the other table. So that one digit cannot be added more than once. When you click on a field with a number, "EventListener" is automatically removed. The function getNumbers() loop the fields in the second table and fills in the next blank field.
I have marked the new things in your code with a comments // NEW CODE LINE
Example:
<!DOCTYPE html>
<html>
<head>
<script>
var timerid;
var secs = 30;
var randomNumber;
var mclics = 0;
var mcorrect = 0;
function begin() {
randomNumber = Math.round(Math.random() * 9);
var atable = document.getElementById("atable");
for (i = 0; i < atable.rows.length; i++) {
for (j = 0; j < atable.rows[i].cells.length; j++) {
var a = Math.ceil(Math.random() * 100);
atable.rows[i].cells[j].innerHTML = a;
// NEW CODE LINE
atable.rows[i].cells[j].addEventListener("click", function () {
getNumbers(this.innerText);
this.removeEventListener("click", arguments.callee);
});
// END NEW CODE LINE
}
}
}
function check(trgt) {
if (trgt.tagName == "TD") {
mclics++
trgt.onclick = false; //for not happen again click//
if ((trgt.innerHTML % randomNumber) == 0) {
mcorrect++ //right clicks
trgt.style.backgroundColor = "green";
}
else {
trgt.style.backgroundColor = "red";
}
}
}
// NEW CODE LINE
function getNumbers(x) {
var target = document.getElementById('second').getElementsByTagName('td');
for (var i = 0; i < target.length; i++) {
if (target[i].innerText.length === 0) {
target[i].innerText = x;
break;
}
}
}
// END NEW CODE LINE
</script>
</head>
<body>
<input type="button" value="Start" onclick="begin()" style="width: 30%"><br>
<p id="anumber"></p>
<table id="atable" border="1" onclick="check(event.target)">
<tr>
<td style="width: 292px; height: 39px;"> </td>
<td style="width: 332px; height: 39px;"></td>
<td style="width: 260px; height: 39px;">
</tr>
<tr>
<td style="width: 292px; height: 46px;"></td>
<td style="width: 332px; height: 46px;"></td>
<td style="width: 260px; height: 46px;">
</tr>
<tr>
<td style="width: 292px; height: 172px;"></td>
<td style="width: 332px; height: 172px;"></td>
<td style="width: 260px; height: 172px;">
</tr>
</table>
<p>Remaining time: </p>
<p id="atimer"></p>
<table id="second" border="1">
<tr>
<td style="width: 292px; height: 39px;"> </td>
</tr>
<tr>
<td style="width: 332px; height: 39px;"></td>
</tr>
<tr>
<td style="width: 292px; height: 46px;"></td>
</tr>
<tr>
<td style="width: 332px; height: 46px;"></td>
</tr>
<tr>
<td style="width: 332px; height: 39px;"></td>
</tr>
<tr>
<td style="width: 332px; height: 39px;"></td>
</tr>
<tr>
<td style="width: 332px; height: 39px;"></td>
</tr>
<tr>
<td style="width: 332px; height: 39px;"></td>
</tr>
<tr>
<td style="width: 332px; height: 39px;"></td>
</tr>
</table>
</body>
</html>
Version 2:
Does not start before pressing the "Start" button. Cleans the contents of both tables when the "Start" button is pressed again.
<!DOCTYPE html>
<html>
<head>
<script>
var timerid;
var secs = 30;
var randomNumber;
// var mclics = 0;
var mcorrect = 0;
function begin() {
// NEW CODE LINE
mcorrect = 0;
var tableA = document.getElementById('atable').getElementsByTagName('td');
for (var i = 0; i < tableA.length; i++) {
tableA[i].style.backgroundColor = '';
tableA[i].removeEventListener("click", getClick);
}
var tableB = document.getElementById('second').getElementsByTagName('td');
for (var i = 0; i < tableB.length; i++) {
tableB[i].innerText = '';
}
// END NEW CODE LINE
randomNumber = Math.round(Math.random() * 9);
var atable = document.getElementById("atable");
for (i = 0; i < atable.rows.length; i++) {
for (j = 0; j < atable.rows[i].cells.length; j++) {
var a = Math.ceil(Math.random() * 100);
atable.rows[i].cells[j].innerHTML = a;
// NEW CODE LINE
atable.rows[i].cells[j].addEventListener("click", getClick);
// END NEW CODE LINE
}
}
}
// function check(trgt) {
// if (trgt.tagName == "TD") {
// mclics++
// trgt.onclick = false; //for not happen again click//
// if ((trgt.innerHTML % randomNumber) == 0) {
// mcorrect++ //right clicks
// trgt.style.backgroundColor = "green";
// }
// else {
// trgt.style.backgroundColor = "red";
// }
// }
// }
// NEW CODE LINE
function getClick() {
getNumbers(this.innerText, this);
this.removeEventListener("click", getClick);
}
function getNumbers(x, y) {
if ((y.innerHTML % randomNumber) == 0) {
mcorrect++ //right clicks
y.style.backgroundColor = "green";
}
else {
y.style.backgroundColor = "red";
}
var target = document.getElementById('second').getElementsByTagName('td');
for (var i = 0; i < target.length; i++) {
if (target[i].innerText.length === 0) {
target[i].innerText = x;
break;
}
}
}
// END NEW CODE LINE
</script>
</head>
<body>
<input type="button" value="Start" onclick="begin()" style="width: 30%">
<br>
<p id="anumber"></p>
<table id="atable" border="1">
<tr>
<td style="width: 292px; height: 39px;"> </td>
<td style="width: 332px; height: 39px;"></td>
<td style="width: 260px; height: 39px;">
</tr>
<tr>
<td style="width: 292px; height: 46px;"></td>
<td style="width: 332px; height: 46px;"></td>
<td style="width: 260px; height: 46px;">
</tr>
<tr>
<td style="width: 292px; height: 172px;"></td>
<td style="width: 332px; height: 172px;"></td>
<td style="width: 260px; height: 172px;">
</tr>
</table>
<p>Remaining time: </p>
<p id="atimer"></p>
<table id="second" border="1">
<tr>
<td style="width: 292px; height: 39px;"> </td>
</tr>
<tr>
<td style="width: 332px; height: 39px;"></td>
</tr>
<tr>
<td style="width: 292px; height: 46px;"></td>
</tr>
<tr>
<td style="width: 332px; height: 46px;"></td>
</tr>
<tr>
<td style="width: 332px; height: 39px;"></td>
</tr>
<tr>
<td style="width: 332px; height: 39px;"></td>
</tr>
<tr>
<td style="width: 332px; height: 39px;"></td>
</tr>
<tr>
<td style="width: 332px; height: 39px;"></td>
</tr>
<tr>
<td style="width: 332px; height: 39px;"></td>
</tr>
</table>
</body>
</html>
So either I did this backward or this is how you wanted it. If you meant like, a long (height) table then this is what you want. If you want a wide table, just switch the secondTable.rows[mclics].cells[0].innerHTML = trgt.innerHTML to secondTable.rows[0].cells[mclics].innerHTML = trgt.innerHTML and reformat the table to only have one row. This code simply takes the innerHTML of the cell that you click and add it to the next table's next spot. There is no check though, so it will error once you fill-up the second table. Good luck!
function check(trgt) {
var secondTable = document.getElementById("second");
if (trgt.tagName == "TD") {
secondTable.rows[mclics].cells[0].innerHTML = trgt.innerHTML
mclics++
trgt.onclick = false; //for not happen again click//
if ((trgt.innerHTML % randomNumber) == 0) {
mcorrect++ //right clicks
trgt.style.backgroundColor = "green";
} else {
trgt.style.backgroundColor = "red";
}
}
}
HTML Table (second):
<table id="second" style="border: 1;" >
<tr><td style="width: 292px; height: 39px;"></td></tr>
<tr><td style="width: 292px; height: 39px;"></td></tr>
<tr><td style="width: 292px; height: 39px;"></td></tr>
<tr><td style="width: 292px; height: 46px;"></td></tr>
<tr><td style="width: 292px; height: 46px;"></td></tr>
<tr><td style="width: 292px; height: 46px;"></td></tr>
<tr><td style="width: 292px; height: 172px;"></td></tr>
<tr><td style="width: 332px; height: 172px;"></td></tr>
<tr><td style="width: 260px; height: 172px;"></td></tr>
</table>```
I have parent child hierarchy data loaded from database into html table structure where i need to enter value in some of leaf node.
When I enter value in any leaf node then recursively do sum in hierarchy up to last parent node.
I need to do this using jquery/javascript and html table tree format.
This is my html
//This is textbox change event.
$(document).on('change', '.item-balance', function () {
if (!$.isNumeric($(this).val())) return false;
calculatehierarchybalance($(this).closest('tr'));
});
//Below is calculation function. Here problem is that it only sum up to single level instead of all the parent of leaf node.
var calculatehierarchybalance = function (currentrow) {
var inpctrl = $(currentrow).find(".item-balance");
var _total = 0;
$.each(currentrow, function () {
var ss = $('tr[data-id=' + $(currentrow).attr('data-parentid') + ']');
//console.log($(ss).attr('data-id'), $(ss).attr('data-parentid'));
if (inpctrl.is('input:text')) {
_total = _total + Number(inpctrl.val());
}
else {
_total = _total + Number($(ss).find('td.td-bal').text().trim());
}
$(ss).find('td[data-readonly=true]').text(_total);
if ($.isNumeric($(ss).attr('data-parentid')))
calculatehierarchybalance($(ss));
});
};
.table {
width: 100%;
max-width: 100%;
margin-bottom: 1rem;
background-color: transparent;
}
.table > thead > tr > th, .table > tbody > tr > th, .table > tfoot > tr > th, .table > thead > tr > td, .table > tbody > tr > td, .table > tfoot > tr > td {
border-top: 1px solid #e7eaec;
border-bottom: 1px solid #e7eaec;
line-height: 1.42857;
padding: 8px;
vertical-align: top;
}
.table-Balance td {
border: 1px solid #eee;
}
.collapse-tr .toggle {
background: url("https://cdn4.iconfinder.com/data/icons/ionicons/512/icon-ios7-minus-empty-128.png");
}
.expand-tr .toggle {
background: url("https://cdn4.iconfinder.com/data/icons/ionicons/512/icon-ios7-plus-empty-128.png");
}
.toggle {
height: 9px;
width: 9px;
display: inline-block;
}
.panel-title {
color: #fff !important;
}
<script src="https://cdnjs.cloudflare.com/ajax/libs/jquery/3.3.1/jquery.min.js"></script>
<table class="table table-balance" id="tblbl">
<thead>
<tr>
<th>Catálogo de Cuentas</th>
<th class="text-right">Balance</th>
</tr>
</thead>
<tbody>
<tr data-depth="0" class="collapse-tr level0" data-id="81" data-parentid="" data-readonly="true"
data-baseaccounttype="1" data-accounttype="1" data-accountid="2">
<td style="padding-left:0px;" class="align-middle"><span class="toggle collapse-tr"></span>1-Activos</td>
<td class="text-right td-bal" data-readonly="true">
0.00 </td>
</tr>
<tr data-depth="1" class=" level1" data-id="82" data-parentid="81" data-readonly="true"
data-baseaccounttype="1" data-accounttype="1" data-accountid="3">
<td style="padding-left:12px;" class="align-middle"><span class=" "></span>1.1-Activos Corrientes</td>
<td class="text-right td-bal" data-readonly="true">
0.00 </td>
</tr>
<tr data-depth="2" class=" level2" data-id="83" data-parentid="82" data-readonly="true"
data-baseaccounttype="1" data-accounttype="2" data-accountid="4">
<td style="padding-left:18px;" class="align-middle"><span class=" "></span>1.1.10-Efectivo y Equivalentes</td>
<td class="text-right td-bal" data-readonly="true">
0.00 </td>
</tr>
<tr data-depth="3" class=" level3" data-id="84" data-parentid="83" data-readonly="true"
data-baseaccounttype="1" data-accounttype="2" data-accountid="5">
<td style="padding-left:24px;" class="align-middle"><span class=" "></span>1.1.10.1-Cajas</td>
<td class="text-right td-bal" data-readonly="true">
0.00 </td>
</tr>
<tr data-depth="4" class=" level4" data-id="85" data-parentid="84" data-readonly="false"
data-baseaccounttype="1" data-accounttype="2" data-accountid="6">
<td style="padding-left:30px;" class="align-middle"><span class=" "></span>1.1.10.1.10-Caja General</td>
<td class="text-right td-bal" data-readonly="false">
<input class="form-control text-right input-sm inputdecimal item-balance" id="Balance" name="Balance" placeholder="Ingresar saldo" type="text" value="0.00" /> </td>
</tr>
<tr data-depth="3" class=" level3" data-id="87" data-parentid="83" data-readonly="true"
data-baseaccounttype="1" data-accounttype="2" data-accountid="8">
<td style="padding-left:24px;" class="align-middle"><span class=" "></span>1.1.10.2-Bancos</td>
<td class="text-right td-bal" data-readonly="true">
0.00 </td>
</tr>
<tr data-depth="4" class=" level4" data-id="88" data-parentid="87" data-readonly="false"
data-baseaccounttype="1" data-accounttype="2" data-accountid="9">
<td style="padding-left:30px;" class="align-middle"><span class=" "></span>1.1.10.2.10-Banco #1 (Cambiar Nombre)</td>
<td class="text-right td-bal" data-readonly="false">
<input class="form-control text-right input-sm inputdecimal item-balance" id="Balance" name="Balance" placeholder="Ingresar saldo" type="text" value="0.00" /> </td>
</tr>
<tr data-depth="4" class=" level4" data-id="86" data-parentid="84" data-readonly="false"
data-baseaccounttype="1" data-accounttype="2" data-accountid="7">
<td style="padding-left:12px;" class="align-middle"><span class=" "></span>1.2-Depósitos sin aplicar</td>
<td class="text-right td-bal">0.00
</td>
</tr>
<tr data-depth="4" class=" level4" data-id="86" data-parentid="84" data-readonly="false"
data-baseaccounttype="1" data-accounttype="2" data-accountid="7">
<td style="padding-left:18px;" class="align-middle"><span class=" "></span>1.2.1-Depósitos sin aplicar 1</td>
<td class="text-right td-bal">
<input class="form-control text-right input-sm inputdecimal item-balance" id="Balance" name="Balance" placeholder="Ingresar saldo" type="text" value="0.00" /> </td>
</tr>
</tbody>
</table>
Expected Output as below image when I entered value in leaf node that will reflect to all related parent node.
Any help would be appreciated.
Thank you.
A bit late for an answer, but I enjoyed giving an answer :)
I chose a bit different approach:
create an object that holds the data recursively
make the value "reactive" by using getters
I guess neither too efficient nor very scalable, but solves the problem in a logically simple way.
// sum the value of immediate children's values
function getRecursiveVal(items) {
return items.length ? items.reduce((a, c) => a + c.val, 0) : 0
}
// recursive object getter
// gets an item by label
function findByLabel(label, item) {
if (item.label === label) {
return item
} else if (item?.length || item?.items?.length) {
let ret
for (let i = 0; i < item.items.length; i++) {
ret = findByLabel(label, item.items[i])
if (ret) {
break;
}
}
return ret
}
}
// array to hold the data
// if readonly is false, then the item's
// beginning val is 0
// if readonly is true, the the items's
// beginning val is the sum of its items vals
const arr = [
{
label: "1-Activos",
get val() { return getRecursiveVal(this.items) },
readonly: true,
items: [
{
label: "1.1-Activos Corrientes",
get val() { return getRecursiveVal(this.items) },
readonly: true,
items: [
{
label: "1.1.10-Efectivo y Equivalentes",
get val() { return getRecursiveVal(this.items) },
readonly: true,
items: [
{
label: "1.1.10.1-Cajas",
get val() { return getRecursiveVal(this.items) },
readonly: true,
items: [
{
label: "1.1.10.1.10-Caja General",
val: 0,
readonly: false,
items: [],
},
],
},
{
label: "1.1.10.2-Bancos",
get val() { return getRecursiveVal(this.items) },
readonly: true,
items: [
{
label: "1.1.10.2.10-Banco #1 (Cambiar Nombre)",
val: 0,
readonly: false,
items: [],
},
],
}
],
}
],
},
{
label: "1.2-Depósitos sin aplicar",
get val() { return getRecursiveVal(this.items) },
readonly: true,
items: [
{
label: "1.2.1-Depósitos sin aplicar 1",
val: 0,
readonly: false,
items: [],
},
],
}
]
},
];
// row template
function rowHtml(data) {
let html = '<tr>'
html += `<td>${ data.label }</td>`
if (data.readonly) {
html += `<td>${ data.val }</td>`
} else {
html += `
<td>
<input
data-inputfor="${ data.label }"
value="${ Number(data.val) }"
/>
</td>
`
}
html += '</tr>'
return html
}
// flattening the object for
// HTML table
function recTableHtml(item) {
let html = rowHtml(item)
if (item?.items?.length) {
html += item.items.map(e => recTableHtml(e)).join("")
}
return html
}
const tbody = document.getElementById("tbody");
function updateTable(container, arr, fn) {
container.innerHTML = arr.map(e => fn(e)).join("")
}
// first paint of the table
(function(container) {
updateTable(tbody, arr, recTableHtml)
})(tbody);
jQuery(document).ready(function($) {
// general action on input
$("body").on("input", "input", function(e) {
const thisLabel = this.getAttribute("data-inputfor")
const item = findByLabel(thisLabel, arr[0])
item.val = Number($(this).val())
updateTable(tbody, arr, recTableHtml)
// setting focus to last char of input
// so there's continuous typing
var value = $(`[data-inputfor="${thisLabel}"]`).val();
$(`[data-inputfor="${thisLabel}"]`).focus().val('').val(value)
})
})
<script src="https://cdnjs.cloudflare.com/ajax/libs/jquery/3.3.1/jquery.min.js"></script>
<table>
<tbody id="tbody"></tbody>
</table>
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.
I'm relatively new to jQuery but more seasoned using html and css.
I'm currently working on creating a new report that displays a nested table with quarterly results.Sample Quarterly Report
When a user clicks the img next to Q1 or Q2 table row - my expectation is for the Week (wk1 - wkn) columns to hide/show (toggle) as needed.
Additionally, when week columns are hidden, i would like the Quartely column(s) to collapse and dynamically show the sum of hidden weeks (wk1 - wkn).
Most of the code is borrowed from other posts but unfortunately, i was unable to find one that collapses and sums nested columns.
Thanks in advance for your help!
$(document).ready(function () {
var mImg = "http://t1.gstatic.com/images?q=tbn:1PS9x2Ho4LHpaM:http://www.unesco.org/ulis/imag/minus.png";
var pImg = "http://t3.gstatic.com/images?q=tbn:4TZreCjs_a1eDM:http://www.venice.coe.int/images/plus.png";
var sum1 = 0;
$('tr').find('.combat1').each(function () {
var combat1 = $(this).text();
if (!isNaN(combat1) && combat1.length !== 0) {
sum1 += parseFloat(combat1);
}
});
var sum2 = 0;
$('tr').find('.combat2').each(function () {
var combat2 = $(this).text();
if (!isNaN(combat2) && combat2.length !== 0) {
sum2 += parseFloat(combat2);
}
});
var sum3 = 0;
$('tr').find('.combat3').each(function () {
var combat3 = $(this).text();
if (!isNaN(combat3) && combat3.length !== 0) {
sum3 += parseFloat(combat3);
}
});
$('.total-combat1').html(sum1);
$('.total-combat2').html(sum2);
$('.total-combat3').html(sum3);
$('.header').click(function() {
//$('td:nth-child(2)').hide();
// if your table has header(th), use this
$('td:nth-child(2),th:nth-child(2)').toggle();
});
});
body {
background: #80dfff;
color: #d5d4d4;
font-family: Helvetica, Arial, sans-serif;
font-size: 12px;
margin: 0;
overflow-x: auto;
padding: 30px;
}
table {
background: white;
border-collapse: collapse;
border: 1px #393939 solid;
color: black;
margin: 1em 1em 1em 0;
}
thead {
border-collapse: collapse;
color: black;
}
th, td {
border: 1px #aaa solid;
padding: 0.2em;
}
<table>
<thead>
<tr><th colspan=8>2015</th></tr>
<tr><th colspan=4 class="header">Q1
<img src="http://t1.gstatic.com/images?q=tbn:1PS9x2Ho4LHpaM:http://www.unesco.org/ulis/imag/minus.png" />
</th>
<th colspan=3 class="header">Q2
<img src="http://t1.gstatic.com/images?q=tbn:1PS9x2Ho4LHpaM:http://www.unesco.org/ulis/imag/minus.png" />
</th>
<th></th>
</tr>
<tr>
<th>WK1</th>
<th>WK2</th>
<th>WK3</th>
<th>WK4</th>
<th>WK1</th>
<th>WK2</th>
<th>WK3</th>
<th>Total</th>
</tr>
</thead>
<tbody>
<tr>
<td class="combat1">8170</td>
<td class="combat1">6504</td>
<td class="combat1">6050</td>
<td class="combat1">6050</td>
<td class="combat1">7050</td>
<td class="combat1">7050</td>
<td class="combat1">7050</td>
<td class="total-combat1"></td>
</tr>
<tr>
<td class="combat2">8500</td>
<td class="combat2">10200</td>
<td class="combat2">7650</td>
<td class="combat2">7650</td>
<td class="combat2">8650</td>
<td class="combat2">8650</td>
<td class="combat2">8650</td>
<td class="total-combat2"></td>
</tr>
<tr>
<td class="combat3">9185</td>
<td class="combat3">5515</td>
<td class="combat3">6185</td>
<td class="combat3">7185</td>
<td class="combat3">9185</td>
<td class="combat3">9185</td>
<td class="combat3">9185</td>
<td class="total-combat3"></td>
</tr>
</tbody>
</table>
If you need to toggle the visibility of Q1 or Q2 you can change the header click event in order to obtain the effect produced in the following snippet.
The problem is to select all the cells of your interest and than toggle the visibility.
One way is to limit the cells selected using the jQuery :lt and :gt plus the css
$(function () {
var mImg = "http://t1.gstatic.com/images?q=tbn:1PS9x2Ho4LHpaM:http://www.unesco.org/ulis/imag/minus.png";
var pImg = "http://t3.gstatic.com/images?q=tbn:4TZreCjs_a1eDM:http://www.venice.coe.int/images/plus.png";
var sum1 = 0;
$('tr').find('.combat1').each(function () {
var combat1 = $(this).text();
if (!isNaN(combat1) && combat1.length !== 0) {
sum1 += parseFloat(combat1);
}
});
var sum2 = 0;
$('tr').find('.combat2').each(function () {
var combat2 = $(this).text();
if (!isNaN(combat2) && combat2.length !== 0) {
sum2 += parseFloat(combat2);
}
});
var sum3 = 0;
$('tr').find('.combat3').each(function () {
var combat3 = $(this).text();
if (!isNaN(combat3) && combat3.length !== 0) {
sum3 += parseFloat(combat3);
}
});
$('.total-combat1').html(sum1);
$('.total-combat2').html(sum2);
$('.total-combat3').html(sum3);
// The new header click event
$('.header').click(function(e) {
var isVisible = false;
var strSelector = '';
var everyTotIndex = 4;
if (this.innerText.trim() == 'Q1') {
everyTotIndex = 4;
strSelector = 'td:not([colspan="4"]):lt(4), th:not([colspan="4"]):lt(4)';
} else {
everyTotIndex = 3;
strSelector = 'td:not([colspan="3"]):lt(7):gt(3), th:not([colspan="3"]):lt(7):gt(3)';
}
$(this).parents('table').find('tr:eq(2), tbody > tr').find(strSelector).css('display', function(index, value) {
if (this.style.display == 'none') {
isVisible = true;
if ((index % everyTotIndex) == 0) {
$(this).parent().find('td[colspan="' + everyTotIndex + '"], th[colspan="' + everyTotIndex + '"]').remove();
}
return '';
}
if ((index % everyTotIndex) == 0) {
if (this.tagName.toLowerCase() == 'th') {
$('<th colspan="' + everyTotIndex + '" class="total">Total</th>').insertBefore($(this));
} else {
$('<td colspan="' + everyTotIndex + '" class="combat1 total">0</td>').insertBefore($(this));
var obj = $(this).parent().find('td[colspan="' + everyTotIndex + '"]');
obj.text(+obj.text() + parseInt(this.textContent));
}
} else {
if (this.tagName.toLowerCase() == 'td') {
var obj = $(this).parent().find('td[colspan="' + everyTotIndex + '"]');
obj.text(+obj.text() + parseInt(this.textContent));
}
}
return 'none';
});
if (isVisible) {
$(this).find('img').attr('src', "http://www.unesco.org/ulis/imag/minus.png");
} else {
$(this).find('img').attr('src', "http://www.unesco.org/ulis/imag/plus.png");
}
});
});
body {
background: #80dfff;
color: #d5d4d4;
font-family: Helvetica, Arial, sans-serif;
font-size: 12px;
margin: 0;
overflow-x: auto;
padding: 30px;
}
table {
background: white;
border-collapse: collapse;
border: 1px #393939 solid;
color: black;
margin: 1em 1em 1em 0;
}
thead {
border-collapse: collapse;
color: black;
}
th, td {
border: 1px #aaa solid;
padding: 0.2em;
}
<script src="http://code.jquery.com/jquery-1.11.3.js"></script>
<table>
<thead>
<tr><th colspan=8>2015</th></tr>
<tr><th colspan=4 class="header">Q1
<img src="http://t1.gstatic.com/images?q=tbn:1PS9x2Ho4LHpaM:http://www.unesco.org/ulis/imag/minus.png" />
</th>
<th colspan=3 class="header">Q2
<img src="http://t1.gstatic.com/images?q=tbn:1PS9x2Ho4LHpaM:http://www.unesco.org/ulis/imag/minus.png" />
</th>
<th></th>
</tr>
<tr>
<th>WK1</th>
<th>WK2</th>
<th>WK3</th>
<th>WK4</th>
<th>WK1</th>
<th>WK2</th>
<th>WK3</th>
<th>Total</th>
</tr>
</thead>
<tbody>
<tr>
<td class="combat1">8170</td>
<td class="combat1">6504</td>
<td class="combat1">6050</td>
<td class="combat1">6050</td>
<td class="combat1">7050</td>
<td class="combat1">7050</td>
<td class="combat1">7050</td>
<td class="total-combat1"></td>
</tr>
<tr>
<td class="combat2">8500</td>
<td class="combat2">10200</td>
<td class="combat2">7650</td>
<td class="combat2">7650</td>
<td class="combat2">8650</td>
<td class="combat2">8650</td>
<td class="combat2">8650</td>
<td class="total-combat2"></td>
</tr>
<tr>
<td class="combat3">9185</td>
<td class="combat3">5515</td>
<td class="combat3">6185</td>
<td class="combat3">7185</td>
<td class="combat3">9185</td>
<td class="combat3">9185</td>
<td class="combat3">9185</td>
<td class="total-combat3"></td>
</tr>
</tbody>
</table>
I tried to figure out what you was trying to do... Correct if me I wrong: you're trying to toggle the set of columns under, for e.g. Q1, when you click on the header column? If so, here the code. I modified your code, I added to nested tables under the main table to organize/ divide the two sets of information so I can select easily with jQuery which one I'm going to toggle.
$(document).ready(function() {
var mImg = "http://t1.gstatic.com/images?q=tbn:1PS9x2Ho4LHpaM:http://www.unesco.org/ulis/imag/minus.png";
var pImg = "http://t3.gstatic.com/images?q=tbn:4TZreCjs_a1eDM:http://www.venice.coe.int/images/plus.png";
var sum1 = 0;
$('tr').find('.combat1').each(function() {
var combat1 = $(this).text();
if (!isNaN(combat1) && combat1.length !== 0) {
sum1 += parseFloat(combat1);
}
});
var sum2 = 0;
$('tr').find('.combat2').each(function() {
var combat2 = $(this).text();
if (!isNaN(combat2) && combat2.length !== 0) {
sum2 += parseFloat(combat2);
}
});
var sum3 = 0;
$('tr').find('.combat3').each(function() {
var combat3 = $(this).text();
if (!isNaN(combat3) && combat3.length !== 0) {
sum3 += parseFloat(combat3);
}
});
$('.header-1').click(function() {
$("#table1").toggle();
});
$('.header-2').click(function() {
$("#table2").toggle();
});
});
body {
color: #d5d4d4;
font-family: Helvetica, Arial, sans-serif;
font-size: 12px;
margin: 0;
overflow-x: auto;
padding: 30px;
}
table {
background: white;
border-collapse: collapse;
border: 1px #393939 solid;
color: black;
margin: 0;
padding: 0;
}
thead {
border-collapse: collapse;
color: black;
}
th,
td,
tr {
border: 1px #aaa solid;
padding: 0;
}
td.combat {
padding: 0.2em;
}
<script src="https://ajax.googleapis.com/ajax/libs/jquery/1.9.0/jquery.min.js"></script>
<table id="myTable">
<thead>
<tr>
<th colspan=2>2015</th>
</tr>
<tr>
<th class="header-1">Q1
<img src="http://t1.gstatic.com/images?q=tbn:1PS9x2Ho4LHpaM:http://www.unesco.org/ulis/imag/minus.png" />
</th>
<th class="header-2">Q2
<img src="http://t1.gstatic.com/images?q=tbn:1PS9x2Ho4LHpaM:http://www.unesco.org/ulis/imag/minus.png" />
</th>
</tr>
</thead>
<tbody>
<tr>
<td>
<table id="table1">
<tr>
<th>WK1</th>
<th>WK2</th>
<th>WK3</th>
<th>WK4</th>
</tr>
<tr>
<td class="combat combat1">8170</td>
<td class="combat combat1">6504</td>
<td class="combat combat1">6050</td>
<td class="combat combat1">6050</td>
</tr>
<tr>
<td class="combat combat1">8170</td>
<td class="combat combat1">6504</td>
<td class="combat combat1">6050</td>
<td class="combat combat1">6050</td>
</tr>
</table>
</td>
<td>
<table id="table2">
<tr>
<th>WK1</th>
<th>WK2</th>
<th>WK3</th>
</tr>
<tr>
<td class="combat combat2">7050</td>
<td class="combat combat2">7050</td>
<td class="combat combat2">7050</td>
</tr>
<tr>
<td class="combat combat2">7050</td>
<td class="combat combat2">7050</td>
<td class="combat combat2">7050</td>
</tr>
</table>
</td>
<td>
<table>
<tr>
<td></td>
</tr>
<tr>
<td></td>
</tr>
<tr>
<td></td>
</tr>
</table>
</td>
</tr>
</tbody>
</table>
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>