Javascript: Sum up columns of a table

Collapse
X
 
  • Time
  • Show
Clear All
new posts
  • dmj07
    New Member
    • Aug 2008
    • 55

    #1

    Javascript: Sum up columns of a table

    Hi all,

    I have a simple table set up in which a user can insert values into the boxes and onkeydown it will sum up the column.

    Table:

    Code:
    <table>
    <tr>
    <td><input type="text" onkeydown="calcTotal(this, 'tot')" /></td>
    <td><input type="text" onkeydown="calcTotal(this, 'tot1')" /></td>
    </tr>
    <tr>    
    <td><input type="text" onkeydown="calcTotalCol(this, 'tot')" /></td>
    <td><input type="text" onkeydown="calcTotalCol(this, 'tot1')" /></td>
    </tr>
    <tr>    
    <td><input type="text" onkeydown="calcTotal(this, 'tot')" /></td>
    <td><input type="text" onkeydown="calcTotal(this, 'tot1')" /></td>       
    </tr>
    <tr>    
    <td><input type="text" id="tot" /></td>
    <td><input id="tot1" type="text" /></td>
    </tr>   
    </table>
    Javascript:

    Code:
    function calcTotal(txtBox, totBox) 
             {
                var col = txtBox.parentNode.parentNode.parentNode;
                var inputs = col.getElementsByTagName("input"); //Get input boxes 
                sum = 0;    //Set sum to 0
    
                for (i=0; i< inputs.length; i++) 
                {
                    if (inputs[i].type == "text") 
                    {
                        if(inputs[i].id.indexOf(totBox) == -1) //Pass id of total text box
                        {
                            if (inputs[i].value != null && inputs[i].value != "") 
                            sum += parseInt(inputs[i].value); //Calculate the total
                        }
                        else
                        {
                            inputs[i].value = sum;  //Store total in box
                        }
                     }
                 }
             }
    I think my problem is I am getting the wrong objects when traversing through the DOM of the table, think I may be getting the tbody rather than the column, so I need help in getting the columns to sum them up if anyone can help.

    Many thanks in advance.
  • RamananKalirajan
    Contributor
    • Mar 2008
    • 608

    #2
    Hi...

    I have just changed some part of your code.... This is one way of summing the column.. you can work in n no.. of ways to find the sum...

    HTML Code

    Code:
    <table> 
    <tr> 
    <td><input type="text" onblur="calcTotal(this, 'tot')" /></td> 
    <td><input type="text" onblur="calcTotal(this, 'tot1')" /></td> 
    </tr> 
    <tr>     
    <td><input type="text" onblur="calcTotal(this, 'tot')" /></td> 
    <td><input type="text" onblur="calcTotal(this, 'tot1')" /></td> 
    </tr> 
    <tr>     
    <td><input type="text" onblur="calcTotal(this, 'tot')" /></td> 
    <td><input type="text" onblur="calcTotal(this, 'tot1')" /></td>        
    </tr> 
    <tr>     
    <td><input type="text" id="tot" /></td> 
    <td><input id="tot1" type="text" /></td> 
    </tr>    
    </table>
    JS Code

    Code:
    <script type="text/javascript">
    function calcTotal(txtBox, totBox)
    {
        var totVal;
        try
        { 
        totVal = document.getElementById(totBox).value;
        if(totVal!= null && totVal!='')
         {
           document.getElementById(totBox).value= eval(parseInt(document.getElementById(totBox).value) + parseInt(txtBox.value));   
         }
         else
         {
            document.getElementById(totBox).value= txtBox.value;   		
         }
        }
        catch(e)
        {}
    }
    </script>
    Regards
    Ramanan Kalirajan

    Comment

    • dmj07
      New Member
      • Aug 2008
      • 55

      #3
      Thank you very much that does the job nicely :)

      Comment

      • acoder
        Recognized Expert MVP
        • Nov 2006
        • 16032

        #4
        Ugh! No need for the eval on line 10 - the parseInt will add up nicely.

        Comment

        • wearsheep
          New Member
          • Dec 2009
          • 4

          #5
          This second solution works really well except (and my javascript understanding is almost nil) the NaN comes up if a field is tabbled through/nothing is entered in a box...

          How can that be addressed?

          Thank you.

          Comment

          • acoder
            Recognized Expert MVP
            • Nov 2006
            • 16032

            #6
            Use the isNaN function. See also http://www.w3schools.com/jsref/jsref_isnan.asp

            Comment

            • wearsheep
              New Member
              • Dec 2009
              • 4

              #7
              Thanks, acoder.

              I figured out a solution for the original question and I managed to edit the preceding code to total both rows and columns.

              Here's the next question: can this be further altered so that changes to the fields can be counted - right now it just keeps adding to the totals but I want it to keep a running total of the current numbers only.

              Possible?

              Javascript
              Code:
              <script type="text/javascript"> 
              function calcTotal(txtBox, totBox, rowBox) 
              { 
              //val(txtBox.item);
              //val(txtBox
               if (txtBox.value.length!=0){
              	var totColVal; 
              	var totRowVal;
                  try 
                  {  
                  totColVal = document.getElementById(totBox).value; 
                  if(totColVal!= null && totColVal!='') 
                   { 
                     document.getElementById(totBox).value= eval(parseInt(document.getElementById(totBox).value) + parseInt(txtBox.value));    
                   } 
                   else 
                   { 
                      document.getElementById(totBox).value= txtBox.value;            
                   } 
                  } 
                  catch(e) 
                  {} 
              	 try 
                  {  
                  totRowVal = document.getElementById(rowBox).value; 
                  if(totRowVal!= null && totRowVal!='') 
                   { 
                   document.getElementById(rowBox).value= (parseInt(document.getElementById(rowBox).value) + parseInt(txtBox.value));    
                   } 
                   else 
                   { 
                      document.getElementById(rowBox).value= txtBox.value;            
                   } 
                  } 
                  catch(e) 
                  {} 
              } }
              </script>
              HTML
              Code:
              </head>
              
              <body>
              <form action="calc.php" method="post" enctype="text" name="multipart/form-data" target="_self"><table>  
              <tr>  
              <td><input type="text" name="1000-0" onblur="calcTotal(this, 'tot0', 'row0')" /></td>  
              <td><input type="text" name="1020-0" onblur="calcTotal(this, 'tot1', 'row0')" /></td>  
              <td><input name="row0" type="text" id="row0" readonly="readonly"/></td>  
              </tr>  
              <tr>      
              <td><input type="text" name="1000-1" onblur="calcTotal(this, 'tot0', 'row1')" /></td>  
              <td><input type="text" name="1020-1" onblur="calcTotal(this, 'tot1', 'row1')" /></td>  
              <td><input name="row1" type="text" id="row1" readonly="readonly"/></td>  
              </tr>  
              <tr>      
              <td><input type="text" name="1000-2" onblur="calcTotal(this, 'tot0', 'row2')" /></td>  
              <td><input type="text" name="1020-2" onblur="calcTotal(this, 'tot1', 'row2')" /></td>   
              <td><input name="row2" type="text" id="row2" readonly="readonly"/></td>        
              </tr>  
              <tr>      
              <td><input name="1000-tot" type="text" id="tot0" readonly="readonly" /></td>  
              <td><input name="1020-tot" type="text" id="tot1" readonly="readonly" /></td>  
              </tr>     
              </table>  <input type="submit" name="submit" value="Submit" /></form>
              </body>
              </html>

              Comment

              • acoder
                Recognized Expert MVP
                • Nov 2006
                • 16032

                #8
                You'll have to recalculate the totals each time. If you want to get a bit more complicated, you could store the values in a 2-dimensional array and change the corresponding value and then recalculate using the array (so that you don't have to access all of the elements each time).

                PS. eval is not required in your code.

                Comment

                • wearsheep
                  New Member
                  • Dec 2009
                  • 4

                  #9
                  two dimensional associative array

                  Thanks again, acoder.

                  (FYI: I really don't know javascript so try not to laugh at this pitiful effort)

                  Here's an attempt at using an array to calculate row/col values. BTW: The column headers are paycodes not just some seeminly random selection of numbers
                  .
                  Javascript
                  Code:
                  <script type="text/JavaScript">
                  function calcTotal(cell,row,col){
                  var total=0;
                  var box={'1000':{},'1001':{},'1002':{},'1005':{},'1007':{},'1003':{},'1020':{},'1035':{},'1038':{},'1045':{},'1066':{},'1067':{},'Other':{}};
                  	box[col][row]=cell;
                  	for (j=0;j<2;j++){
                  		if (box[col][j]>=0){
                  			total+=(box[col][j]);
                  			}
                  		}
                  document.getElementById(col).value;
                  document.getElementById(row).value;
                  }
                  </script>
                  HTML
                  Code:
                  <table border=1px>
                    <tr>
                      <th>Day</th><th>Date</th><th>1000</th><th>1005</th><th>Other</th><th>Total hrs</th><th>Shift Diff</th>
                    </tr>
                    <tr>
                      <td>mon</td><td>12/24</td>
                      <td><input name='1000-0' id='1000-0' type='text' size='2' onblur='calcTotal(this,'0', '1000' )'/></td>
                      <td><input name='1005-0' id='1005-0' type='text' size='2' onblur='calcTotal(this,'0', '1005' )'/></td>
                      <td><input name='Other-0' id='Other-0' type='text' size='2' onblur='calcTotal(this,'0', 'Other' )'/></td>
                      <td><input name='total-0' id='0' type='text' size='2' /></td>
                      <td><input name='1007-0' id='1007-0' type='text' size='2' /></td>
                    </tr>
                    <tr>
                      <td>tue</td><td>12/25</td>
                      <td><input name='1000-1' id='1000-1' type='text' size='2' onblur='calcTotal(this,'1', '1000' )'/></td>
                      <td><input name='1005-1' id='1005-1' type='text' size='2' onblur='calcTotal(this,'1', '1005' )'/></td>
                      <td><input name='Other-1' id='Other-1' type='text' size='2' onblur='calcTotal(this,'1', 'Other' )'/></td>
                      <td><input name='total-1' id='1' type='text' size='2' /></td>
                      <td><input name='1007-1' id='1007-1' type='text' size='2' /></td>
                    </tr>
                    <tr>
                      <td>wed</td><td>12/26</td>
                      <td><input name='1000-2' id='1000-2' type='text' size='2' onblur='calcTotal(this,'2', '1000' )'/></td>
                      <td><input name='1005-2' id='1005-2' type='text' size='2' onblur='calcTotal(this,'2', '1005' )'/></td>
                      <td><input name='Other-2' id='Other-2' type='text' size='2' onblur='calcTotal(this,'2', 'Other' )'/></td>
                      <td><input name='total-2' id='2' type='text' size='2' /></td>
                      <td><input name='1007-2' id='1007-2' type='text' size='2' /></td>
                    </tr>
                   <tr>
                    <td colspan='2' align='right'>totals</td>
                      <td><input name='1000' id='1000' type='text' size='2'/></td>
                      <td><input name='1005' id='1005' type='text' size='2'/></td>
                      <td><input name='Other' id='Other' type='text' size='2'/></td>
                      <td><input name='total' id='total' type='text' size='2'/></td>
                      <td><input name='1007' id='1007' type='text' size='2'/></td>
                    </tr>
                  </table>
                  One big question: Are the numbers stored in the array for the session? or will the array be reset when the function is executed? and if the latter...how can the values be preserved for the session?

                  Another question - Why won't box[i] work for box[box[i]][i] - is that recursive? I have to admit to being a little lost in the array...

                  The last two lines are just a hail-mary that I pulled from the preceding code. So how crazy is this code, anyway? rotfl or lmao?

                  Thank you!

                  Comment

                  • wearsheep
                    New Member
                    • Dec 2009
                    • 4

                    #10
                    So I've pretty much figured this one out but am still trying to allow only numeric entries (including decimals)...

                    ended up abandoning the 2xArray and decided to just loop through each value for a given row/column - so far, so good.

                    One odd thing - the columns wouldn't total until I placed that loop first - any ideas on why that would be?

                    Javascript
                    Code:
                    function calculate(col, row){
                    var numericExpression = /^[0-9]+$/; //verify numeric - needs to allow for decimals though...hmmm...
                    	if(document.getElementById(col+"-"+row).value.match(numericExpression)){
                    var input=0;  //initalize variable to get entered value
                    var rowTot=0; //initalize variable to capture row totals
                    var colTot=0; //initalize variable to capture column totals
                    //setup up array for paycodes/column headers 
                    codes=new Array('1000','1001','1002','1005','1007','1003','1020','1035','1038','1045','1066','1067','Other'); 
                    //loop through all of the text fields for a given column and total them
                    		for (i=0;i<2;i++){
                    		input=(document.getElementById(col+'-'+i).value)*1
                    		colTot=colTot+input;
                    		document.getElementById(col).value = colTot;
                    		}
                    //loop through all of the text fields for a given row and total them
                    		for (j=0;j<13;j++){
                    		input=(document.getElementById(((codes[j])+'-'+row)).value)*1
                    		rowTot=rowTot+input;
                    		document.getElementById('row'+row).value = rowTot;
                    		}
                    	}
                    	//if the entry isn't numeric then return no value
                    	else {document.getElementById(col+"-"+row).value="";}
                    }
                    html
                    Code:
                    Enter numbers here:<br>
                    
                    <input name="1000-0" id="1000-0" type="text"  onblur="calculate('1000','0')">
                    <input name="1001-0" id="1001-0" type="text"  onblur="calculate('1001','0')">
                    <input name="row0" type="text" id="row0" readonly="readonly">
                    <br>
                    <input name="1000-1" id="1000-1" type="text"  onblur="calculate('1000','1')">
                    <input name="1001-1" id="1001-1" type="text"  onblur="calculate('1001','1')">
                    <input name="row1" type="text" id="row1" readonly="readonly">
                    <br>
                    <input name="1000" id="1000" type="text">
                    <input name="1001" id="1001" type="text">
                    <br>

                    Comment

                    • Dormilich
                      Recognized Expert Expert
                      • Aug 2008
                      • 8694

                      #11
                      2 notes from my side:

                      id values must only start with a letter or underscore, anything else is browser courtsy.

                      this and this thread also deal with summing up a table, maybe they give you some more insight.

                      Comment

                      • acoder
                        Recognized Expert MVP
                        • Nov 2006
                        • 16032

                        #12
                        Originally posted by wearsheep
                        So I've pretty much figured this one out but am still trying to allow only numeric entries (including decimals)...
                        Either use a floating point regular expression, e.g. something like: /^[0-9]+\.[0-9]{2}$/ or parseFloat with isNaN

                        One odd thing - the columns wouldn't total until I placed that loop first - any ideas on why that would be?
                        What would happen?

                        Comment

                        • Mozzi
                          New Member
                          • May 2010
                          • 4

                          #13
                          I have a form. Diffrent fields that add up to a sub total. I need to sub totals to autocomplete the TOTAL sum??? I have tried a few things.. but it did not work. Im quite new to this.. I have used some code examples from the site.. (thanks)...

                          I just need to TOTAL SUM to display when i add some numericals to the top fields?? where am I going wrong???

                          Code:
                          <html>
                          <head>
                           
                          <script type="text/JavaScript">
                          function calculate(col, row){
                          var numericExpression = /^[0-9]+$/; //verify numeric - needs to allow for decimals though...hmmm...
                              if(document.getElementById(col+"-"+row).value.match(numericExpression)){
                          var input=0;  //initalize variable to get entered value
                          var rowTot=0; //initalize variable to capture row totals
                          var colTot=0; //initalize variable to capture column totals
                          //setup up array for paycodes/column headers 
                          codes=new Array('1000','1001','1002','1005','1007','1003','1020','1035','1038','1045','1066','1067','Other'); 
                          //loop through all of the text fields for a given column and total them
                                  for (i=0;i<2;i++){
                                  input=(document.getElementById(col+'-'+i).value)*1
                                  colTot=colTot+input;
                                  document.getElementById(col).value = colTot;
                                  }
                          //loop through all of the text fields for a given row and total them
                                  for (j=0;j<13;j++){
                                  input=(document.getElementById(((codes[j])+'-'+row)).value)*1
                                  rowTot=rowTot+input;
                                  document.getElementById('row'+row).value = rowTot;
                                  }
                              }
                              //if the entry isn't numeric then return no value
                              else {document.getElementById(col+"-"+row).value="";}
                          }
                           
                          function updatesum() {
                          document.form.sum.value = (document.form.sum1.value -0) + (document.form.sum2.value -0);
                          }
                           
                          </script>
                           
                          </head>
                           
                          <body>
                           
                          <p>Enter numbers here:<br>
                          <form name="form"  >
                            <p>
                              <input name="1000-0" id="1000-0" type="text"  onblur="calculate('1000','0')" >
                              <input name="1001-0" id="1001-0" type="text"  onblur="calculate('1001','0')" >
                              <br>
                              <input name="1000-1" id="1000-1" type="text"  onblur="calculate('1000','1')" >
                              <input name="1001-1" id="1001-1" type="text"  onblur="calculate('1001','1')" >
                              <br>
                              <br />
                              sub total &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;sub total<br />
                              <input name="sum1" id="1000" type="text" onblur="updatesum()" >
                              <input name="sum2" id="1001" type="text" onblur="updatesum()" >
                              <br />
                              <br />
                              Total Sum:
                              <input name="sum" readonly  />
                          </form>
                          </body>
                          </html>

                          Comment

                          • RamananKalirajan
                            Contributor
                            • Mar 2008
                            • 608

                            #14
                            In the Line Number 24, You are accessing an element with the id ('row'+row). But in the HTML, there is no element with id like that. Check for that. That is the problem.

                            Thanks and Regards
                            Ramanan Kalirajan

                            Comment

                            Working...