3

Basically I want to update an Input field with the sum of all above Input Fields.

This is a part of HTML within tag:

<tr>
                <td width="20%">Admission Fee:</td>
                <td width="80%"><input onchange="findTotal()" type="text" class="input_box" name="admission_fee" id="fee" size="5" value="" maxlength="6" oninput="this.value = this.value.replace(/[^0-9]/, \'\');"></td>
            </tr>
            <tr>
                <td width="20%">Annual Fee:</td>
                <td width="80%"><input onchange="findTotal()" type="text" class="input_box" name="annual_fee" id="fee" size="5" value="" maxlength="6" oninput="this.value = this.value.replace(/[^0-9]/, \'\');"></td>
            </tr>
            <tr>
                <td width="20%">Paper Money Fee:</td>
                <td width="80%"><input onchange="findTotal()" type="text" class="input_box" name="paper_money_fee" id="fee" size="5" value="" maxlength="6" oninput="this.value = this.value.replace(/[^0-9]/, \'\');"></td>
            </tr>
            <tr>
                <td width="20%">Monthly Fee:</td>
                <td width="80%"><input onchange="findTotal()" type="text" class="input_box" name="monthly_fee" id="fee" size="5" value="" maxlength="6" oninput="this.value = this.value.replace(/[^0-9]/, \'\');"></td>
            </tr>
            <tr>
                <td width="20%">Remaining Balance:</td>
                <td width="80%"><input onchange="findTotal()" type="text" class="input_box" name="remaining_balance" id="fee" size="5" value="" maxlength="6" oninput="this.value = this.value.replace(/[^0-9]/, \'\');"></td>
            </tr>
            <tr>
                <td class="school_trow2" width="20%">Total Fee:</td>
                <td class="school_trow2" style="padding: 3px 0;" width="80%"><input type="text" class="input_box" style="background: #8CDFFF; border: 1px solid #006991; color: #000;" name="total_fee" id="total_fee" size="5" value="" disabled></td>
            </tr>

And this is the Javascript I am Using:

<script type="text/javascript">
        function findTotal()
        {
            var arr = document.getElementById(\'fee\');
            var tot=0;
            for(var i=0;i<arr.length;i++)
            {
                if(parseInt(arr[i].value))
                {
                    tot += parseInt(arr[i].value);
                }
            }
            document.getElementById(\'total_fee\').value = tot;
        }
        </script>

Any help would be appreciated.

Imran Omer
  • 701
  • 1
  • 8
  • 20

3 Answers3

3

This is what I've come up with.

  • You are using same Id for multiple elements. I added the same class to the elements instead
  • You are using <input type='text' then checking for numbers using regex. A better approach would be to just use <input type='number'
  • Since maxlength does not work on type='number', I have used max to handle 6 digit limit.

function findTotal() {
  const fees = document.querySelectorAll(".fee");
  const total = document.querySelector("#total_fee");
  let sum = 0;
  
  fees.forEach(fee => {
     if(fee.valueAsNumber){
     sum += fee.valueAsNumber;
     }      
  });
  total.value = sum;    
}
<tr>
   <td width="20%">Admission Fee:</td>
   <td width="80%"><input onchange="findTotal()" type="number" class="input_box fee" name="admission_fee" value="" min='0' max='999999'></td>
</tr>
<tr>
   <td width="20%">Annual Fee:</td>
   <td width="80%"><input onchange="findTotal()" type="number" class="input_box fee" name="annual_fee" value="" min='0' max='999999'></td>
</tr>
<tr>
   <td width="20%">Paper Money Fee:</td>
   <td width="80%"><input onchange="findTotal()" type="number" class="input_box fee" name="paper_money_fee" value="" min='0' max='999999'></td>
</tr>
<tr>
   <td width="20%">Monthly Fee:</td>
   <td width="80%"><input onchange="findTotal()" type="number" class="input_box fee" name="monthly_fee" value="" min='0' max='999999'></td>
</tr>
<tr>
   <td width="20%">Remaining Balance:</td>
   <td width="80%"><input onchange="findTotal()" type="number" class="input_box fee" name="remaining_balance" value="" min='0' max='999999'></td>
</tr>
<tr>
   <td class="school_trow2" width="20%">Total Fee:</td>
   <td class="school_trow2" style="padding: 3px 0;" width="80%"><input type="text" class="input_box" style="background: #8CDFFF; border: 1px solid #006991; color: #000;" name="total_fee" id="total_fee" size="5" value="" disabled></td>
</tr>
ahsan
  • 1,409
  • 8
  • 11
2
  1. Never use the same id for more than one element. This defeats the whole purpose. :)

  2. Change the class name on the total input field to something other than input_box. That way you can select all other <input>s by using document.querySelectorAll('.input_box'). Than traverse them as you did with arr and sum the values, etc.

        function findTotal()
        {
            var arr = document.querySelectorAll('.input_box');
            var tot=0;
            for(var i=0;i<arr.length;i++)
            {
                if(parseInt(arr[i].value))
                {
                    tot += parseInt(arr[i].value);
                }
            }
            document.getElementById(\'total_fee\').value = tot;
        }

Documentation on document.querySelectorAll()

Philip
  • 2,888
  • 2
  • 24
  • 36
  • One issue with this code that the sum is updating irregularly. I mean if I add 2+2+2 then it shows 6 but if I remove any thing from above then the sum add 2 again. I don't know why but there is some issue in your code. – Imran Omer Sep 27 '21 at 06:44
  • Not sure, I only replaced the `document.querySelectorAll('.input_box')` part. If the input field of the total does not have the `input_box` class name, it should select only those other inputs. But maybe there are others on the page with the same class name? – Philip Sep 27 '21 at 06:48
2

Do what Philip and Ahsan Khan said about the HTML and using classes instead of ids for that.

Then use map to parse each value into a integer (or use parseFloat if you want float). Finally, use reduce to sum everything.

const findTotal = () => {
    const fees = [...document.querySelectorAll('.fee')].map(x => parseInt(x.value));
    const total = fees.reduce((a, b) => a + b);
    document.getElementById('total_fee').value = total;
}

Documentation on map

Documentation on reduce

aloisdg
  • 22,270
  • 6
  • 85
  • 105
  • just out of curiosity, wouldn't adding `map` and `reduce` increase the complexity to `O(2N)` compared to writing the logic in `forEach` to make it `O(N)`? or is the difference isn't significant? (P.S I am still pretty novice in JS) – ahsan Sep 27 '21 at 06:46
  • 1
    First you could `parseInt` in the `reduce`'s lambda if you want, but secondly, it really doesn't matter both O(2n) and O(n) are linear (more about that https://stackoverflow.com/questions/25777714/which-algorithm-is-faster-on-or-o2n) – aloisdg Sep 27 '21 at 06:50
  • 1
    This was helpful, Thank you Aloisdg! – ahsan Sep 27 '21 at 06:52