ZombieDivision
ZombieDivision

Reputation: 183

automatic summation of values ​/ looping of the code

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:

  1. 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:

  1. ultimately, class = actual inputs will be readonly

  2. 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

Answers (2)

blex
blex

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

Zohaib Ijaz
Zohaib Ijaz

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

Related Questions