Reputation: 183
Description of the situation:
I have time inputs described in class = "start" and time inputs described in class = "end". The difference is calculated based on the equation 'end-start = actual' 'Actual' are time inputs. Actual inputs should add up and write to the input with id = "sum_actual" (type = text)
Problem:
I have two problems in this question:
a) I don't know how to loop the code that sums up individual inputs class = actual, ultimately there are over 30
b) the code is written in such a way that I have to enter the time manually in the input class = actual so that it updates to the whole sum, when the result comes automatically calculated, it does not add up
Notes:
ultimately, class = actual inputs will be readonly
ultimately there are several other columns with inputs (unimportant ) between the start and end and actual inputs (cosmetics, I pay attention to the way of writing the code)
My code/I tried this code above in javascript is to be improved
//code that sums values from the actual class / should loop it
function msToTime(duration) {
var minutes = Math.floor((duration / (1000 * 60)) % 60),
hours = Math.floor(duration / (1000 * 60 * 60));
hours = hours < 10 ? "0" + hours : hours;
minutes = minutes < 10 ? "0" + minutes : minutes;
return hours + ":" + minutes;
}
console.log(msToTime(300000));
function sum_diff() {
zxc = document.getElementById("actual_1").value;
xcz = document.getElementById("actual_2").value;
czx = document.getElementById("actual_3").value;
zxc = zxc.split(":");
xcz = xcz.split(":");
czx = czx.split(":");
var zxcDate = new Date(0, 0, 0, zxc[0], zxc[1], 0);
var xczDate = new Date(0, 0, 0, xcz[0], xcz[1], 0);
var czxDate = new Date(0, 0, 0, czx[0], czx[1], 0);
var zxcMs =
zxcDate.getHours() * 60 * 60 * 1000 +
zxcDate.getMinutes() * 60 * 1000;
var xczMs =
xczDate.getHours() * 60 * 60 * 1000 +
xczDate.getMinutes() * 60 * 1000;
var czxMs =
czxDate.getHours() * 60 * 60 * 1000 +
czxDate.getMinutes() * 60 * 1000;
var ms = zxcMs + xczMs + czxMs;
return msToTime(ms);
}
var elements = document.getElementsByClassName("actual");
for (var i = 0; i < elements.length; i++) {
elements[i].addEventListener("change", function(e) {
document.getElementById("sum_actual").value = sum_diff();
});
}
// code calculating differences start from end and writing to actual / do not touch it
function diff(start, end) {
start = start.split(":");
end = end.split(":");
const startDate = new Date(0, 0, 0, start[0], start[1], 0);
const endDate = new Date(0, 0, 0, end[0], end[1], 0);
let diff = endDate.getTime() - startDate.getTime();
const hours = Math.floor(diff / 1000 / 60 / 60);
diff -= hours * 1000 * 60 * 60;
const minutes = Math.floor(diff / 1000 / 60);
return (hours < 9 ? "0" : "") + hours + ":" + (minutes < 9 ? "0" : "") + minutes;
}
document.querySelector('table').addEventListener('change', function (e) {
const classList = e.target.classList
if (classList.contains('start') || classList.contains('end')) {
//retrieve the associated inputs
const tr = e.target.parentNode.parentNode
const [start, end, actual] = [...tr.querySelectorAll('.start,.end,.actual')]
const value = diff(start.value, end.value)
actual.value = value
}
})
<table>
<tbody>
<tr>
<td><input class="start" type="time"/></td>
<td><input class="end" type="time"/></td>
<td><input class="actual" type="time" id="actual_1" value="00:00" /></td>
</tr>
<tr><td><input class="actual" type="time" id="actual_2" value="00:00" /></td></tr>
<tr><td><input class="actual" type="time" id="actual_3" value="00:00" /></td></tr>
</tbody>
<tfoot>
<tr><th><input type="text" id="sum_actual" readonly /></th></tr>
</tfoot>
</table>
Note: thanks, it turned out that I have a problem with the counting script and it counts only to 99:59, can you change this limit? to show hours until 300:00?
Upvotes: 0
Views: 61
Reputation: 25634
When confronted with this type of situations, I like to break my big problem into really small problems, and make really small functions which do one thing, but do it well:
const actuals = [...document.getElementsByClassName("actual")];
document.querySelector('table').addEventListener('change', function(e) {
const classList = e.target.classList;
if (classList.contains('start') || classList.contains('end')) {
//retrieve the associated inputs
const tr = e.target.parentNode.parentNode;
const [start, end, actual] = [...tr.querySelectorAll('.start,.end,.actual')];
const value = diff(start.value, end.value);
actual.value = value;
updateActualSum();
}
});
// Update total duration once on load
updateActualSum();
function msToTime(duration) {
const minutes = Math.floor((duration / (1000 * 60)) % 60),
hours = Math.floor(duration / (1000 * 60 * 60));
return twoOrMoreDigits(hours) + ":" + twoOrMoreDigits(minutes);
}
function twoOrMoreDigits(n) {
return n < 10 ? '0' + n : n;
}
function timeToMs(time) {
if (time) { // may be "" if the value is not set
const [hours, minutes] = time.split(":").map(str => parseInt(str, 10));
return (hours * 60 + minutes) * 60 * 1000;
}
return 0;
}
function sum_diff() {
const sum = actuals.reduce((acc, el) => acc + timeToMs(el.value), 0);
return msToTime(sum);
}
function diff(start, end) {
return msToTime(timeToMs(end) - timeToMs(start));
}
function updateActualSum() {
document.getElementById('sum_actual').value = sum_diff();
}
body {font-family: Arial, Helvetica, sans-serif; } table { border-collapse: collapse; } td, th { border: 1px solid #ddd; padding: .2rem; } input[readonly] { background: #f5f5f5; border: none; font-family: inherit; text-align: center; padding: .2rem; }
<table>
<tbody>
<thead>
<tr>
<th>Start</th>
<th>End</th>
<th>Duration</th>
</tr>
</thead>
<tr>
<td><input class="start" type="time" /></td>
<td><input class="end" type="time" /></td>
<td><input class="actual" type="time" id="actual_1" value="00:00" readonly /></td>
</tr>
<tr>
<td><input class="start" type="time" /></td>
<td><input class="end" type="time" /></td>
<td><input class="actual" type="time" id="actual_2" value="00:00" readonly /></td>
</tr>
<tr>
<td><input class="start" type="time" /></td>
<td><input class="end" type="time" /></td>
<td><input class="actual" type="time" id="actual_2" value="00:00" readonly /></td>
</tr>
<tr>
<td><input class="start" type="time" /></td>
<td><input class="end" type="time" /></td>
<td><input class="actual" type="time" id="actual_2" value="00:00" readonly /></td>
</tr>
<tr>
<td><input class="start" type="time" /></td>
<td><input class="end" type="time" /></td>
<td><input class="actual" type="time" id="actual_3" value="00:00" readonly /></td>
</tr>
</tbody>
<tfoot>
<tr>
<th colspan="3"><input type="text" id="sum_actual" readonly /></th>
</tr>
</tfoot>
</table>
Upvotes: 1
Reputation: 22885
Get all actual
values in an array and then using moment, calculate the sum duration
//const durations = document.getElementsByClassName('actual').map(input => input.value);
// And let say, we got following durations
const durations = ['01:30', '05:00', '10:20'];
const totalDuration = durations.slice(1)
.reduce((prev, cur) => moment.duration(cur).add(prev),
moment.duration(durations[0]));
const requiredOutput = `${totalDuration.asHours().toFixed(0)}:${totalDuration.minutes().toString().padStart(2, '0')}`;
console.log(requiredOutput)
<script src="https://cdnjs.cloudflare.com/ajax/libs/moment.js/2.24.0/moment.min.js"></script>
Upvotes: 0