Sum table rows and columns

2020-07-24 03:29发布

问题:

I have a table and I want to allow submitting the form if and only if the total of each row must be =100 not less nor more and the total of each column must be <=100 and not more than 100

This is the old scenario each row and each column must be = 100.

Demo CODE:

<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.3/jquery.min.js"></script>
<script type="text/javascript">
$(document).ready(function(){
disableSave();

$(".sum").on("input", function() {
  sumThisClass("1");
  sumThisClass("2");
  sumThisClass("3");
  sumThisClass("4");
  sumThisClass("5");
  sumThisClass("6");
  sumThisClass("7");
  validateForm();
});

function validateForm() {
  var hasError = $(".error").length > 0;
  if (hasError) {
    disableSave();
    return;
  }
  
  var expectedTotal = $(".total").length * 100;
  console.log(expectedTotal, getCurrentTotal());
  if (expectedTotal == getCurrentTotal()) {
    enableSave();
  }
  else {
    disableSave();
  }
}

function getCurrentTotal() {
    var sumTotal = 0;
    $(".total").each(function (index, el) {
    var elValue = parseInt($(el).text());
    if (!isNaN(elValue)) {
      sumTotal += parseInt($(el).text());
    }
  });
  return sumTotal;
}

function disableSave() {
  $("#btn-save").prop("disabled", true);
}

function enableSave() {
  $("#btn-save").prop("disabled", false);
}

function sumThisClass(className) {

  var sumTotal = 0;
  $("." + className).each(function(index, el) {
    var elValue = parseInt($(el).val());
    if (!isNaN(elValue)) {
      sumTotal += parseInt($(el).val());
    }
  });
  
  $(".sum-" + className).text(sumTotal);

  if (sumTotal > 100) {
    $(".sum-" + className).append("<div class='error'>cannot be greater than 100</div>");
  }

}
});
</script>
<form action="test.php" method="post">
<table>
  <tr>
    <td></td>
    <td></td>
    <td></td>
    <td></td>
    <td>Total</td>
  </tr>
  <tr>
    <td></td>
    <td>
      <input type="number" class="sum 1 5" min="0" max="100">
    </td>
    <td>
      <input type="number" class="sum 1 6" min="0" max="100">
    </td>
    <td>
      <input type="number" class="sum 1 7" min="0" max="100">
    </td>
    <td class="total sum-1"></td>
  </tr>
  <tr>
    <td></td>
    <td>
      <input type="number" class="sum 2 5" min="0" max="100">
    </td>
    <td>
      <input type="number" class="sum 2 6" min="0" max="100">
    </td>
    <td>
      <input type="number" class="sum 2 7" min="0" max="100">
    </td>
    <td class="total sum-2"></td>
  </tr>
  <tr>
    <td>TOTAL</td>
    <td class="total sum-5"></td>
    <td class="total sum-6"></td>
    <td class="total sum-7"></td>
  </tr>
</table>

<input type="submit" name="save" value="SAVE" id="btn-save"/>

Demo Link

I tried to change it but I couldn't succeed.

回答1:

var isvalid=true;
$( document ).ready(function() {
    $("#test").prop("disabled",true);
    $(".tabbody input[type=number]").blur(function(){
        validateSubmit();
    });
});
function validateSubmit()
{
    var retval = sumRowVals();
    $("#test").prop("disabled",!retval);
    $("#msgdiv").html(retval ? "":"Invalid inputs!!!");
}
function sumRowVals()
{
    isvalid=true;
    resetFigs();
    var rindx=1;
    $(".tabbody tr").each(function(){
        var temp=0;
        var cindx=1;
        $("input[type=number]",this).each(function(){
            var elval = !isNaN($(this).val()) ? parseInt($(this).val()):0;
            var sumcol = $("#ccol"+cindx);
            $(sumcol).html(parseInt($(sumcol).html())+elval);
            temp=temp+elval;
            cindx++;
            if(elval > 100){isvalid=false;}
            if(parseInt($(sumcol).html()) > 100){isvalid=false;}
        });
        if(rindx != $('.tabbody tr').length)
        {
            if(temp != 100){isvalid=false;}
            $("#rcol"+rindx).html(temp);
        }
        rindx++;
    });
    return isvalid;
}
function resetFigs()
{
    $('*[id*=ccol]').each(function() {
    $(this).html("0");
});
}
function SubmitForm()
{
    // your form submit code
}
<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js"></script>
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
<html xmlns="http://www.w3.org/1999/xhtml">
<head>
<meta http-equiv="Content-Type" content="text/html; charset=utf-8" />
<title>Untitled Document</title>
<script src="js/jquery2.0.2.min.js"></script>
</head>

<body>
<table border=1 cellpadding="5">
<tbody class='tabbody'>
    <tr>
        <td><input type="number" id="col1" min="0" max="100"></td>
        <td><input type="number" id="col2" min="0" max="100"></td>
        <td><input type="number" id="col3" min="0" max="100"></td>
        <td id="rcol1"></td>
    </tr>
    <tr>
        <td><input type="number" id="col1" min="0" max="100"></td>
        <td><input type="number" id="col2" min="0" max="100"></td>
        <td><input type="number" id="col3" min="0" max="100"></td>
        <td id="rcol2"></td>
    </tr>
    <tr>
      <td id="ccol1"></td>
      <td id="ccol2"></td>
      <td id="ccol3"></td>
        <td>
          <input type="button" name="test" id="test" value="Save" onclick="SubmitForm()" />
</td>
    </tr> 

</tbody>
</table>
<div id="msgdiv" style="color:red;line-height:30px"></div>
</body>
</html>

This is a rough idea:

<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
<html xmlns="http://www.w3.org/1999/xhtml">
<head>
<meta http-equiv="Content-Type" content="text/html; charset=utf-8" />
<title>Untitled Document</title>
<script src="js/jquery2.0.2.min.js"></script>
<script>
var isvalid=true;
$( document ).ready(function() {
    $("#test").prop("disabled",true);
    $(".tabbody input[type=number]").blur(function(){
        validateSubmit();
    });
});
function validateSubmit()
{
    var retval = sumRowVals();
    $("#test").prop("disabled",!retval);
    $("#msgdiv").html(retval ? "":"Invalid inputs!!!");
}
function sumRowVals()
{
    isvalid=true;
    resetFigs();
    var rindx=1;
    $(".tabbody tr").each(function(){
        var temp=0;
        var cindx=1;
        $("input[type=number]",this).each(function(){
            var elval = !isNaN($(this).val()) ? parseInt($(this).val()):0;
            var sumcol = $("#ccol"+cindx);
            $(sumcol).html(parseInt($(sumcol).html())+elval);
            temp=temp+elval;
            cindx++;
            if(elval > 100){isvalid=false;}
            if(parseInt($(sumcol).html()) > 100){isvalid=false;}
        });
        if(rindx != $('.tabbody tr').length)
        {
            if(temp != 100){isvalid=false;}
            $("#rcol"+rindx).html(temp);
        }
        rindx++;
    });
    return isvalid;
}
function resetFigs()
{
    $('*[id*=ccol]').each(function() {
    $(this).html("0");
});
}
function SubmitForm()
{
    // your form submit code
}
</script>
</head>

<body>
<table border=1 cellpadding="5">
<tbody class='tabbody'>
    <tr>
        <td><input type="number" id="col1" min="0" max="100"></td>
        <td><input type="number" id="col2" min="0" max="100"></td>
        <td><input type="number" id="col3" min="0" max="100"></td>
        <td id="rcol1"></td>
    </tr>
    <tr>
        <td><input type="number" id="col1" min="0" max="100"></td>
        <td><input type="number" id="col2" min="0" max="100"></td>
        <td><input type="number" id="col3" min="0" max="100"></td>
        <td id="rcol2"></td>
    </tr>
    <tr>
      <td id="ccol1"></td>
      <td id="ccol2"></td>
      <td id="ccol3"></td>
        <td>
          <input type="button" name="test" id="test" value="Save" onclick="SubmitForm()" />
</td>
    </tr> 

</tbody>
</table>
<div id="msgdiv" style="color:red;line-height:30px"></div>
</body>
</html>


回答2:

Hope it's gonna work for you

$(document).ready(function(){

    disableSave();

    $(".sum").on("input", function() {
      sumThisClass("1");
      sumThisClass("2");
      sumThisClass("3");
      sumThisClass("4");
      sumThisClass("5");
      sumThisClass("6");
      sumThisClass("7");
      validateForm();
    });

    function validateForm() {
      var hasError = $(".error").length > 0;
      if (hasError) {
        disableSave();
        return;
      }

      if( tmp['sum_1'] <= 100 && 
          tmp['sum_2'] <= 100 && 
          tmp['sum_5'] <= 100 && 
          tmp['sum_6'] <= 100 && 
          tmp['sum_7'] <= 100) {
          enableSave();
      } else {
        disableSave();
      }
    }

    function getCurrentTotal() {
      var sumTotal = 0;
      $(".total").each(function (index, el) {
        var elValue = parseInt($(el).text());
        if (!isNaN(elValue)) {
          sumTotal += parseInt($(el).text());
        }
      });
      return sumTotal;
    }
    function disableSave() {
      $("#btn-save").prop("disabled", true);
    }
    function enableSave() {
      $("#btn-save").prop("disabled", false);
    }
    var tmp = {
      sum_1:null,
      sum_2:null,
      sum_5:null,
      sum_6:null,
      sum_7:null
    };
    function sumThisClass(className) {

      var sumTotal = 0;

      $("." + className).each(function(index, el) {
        var elValue = parseInt($(el).val());
        if (!isNaN(elValue)) {
          sumTotal += parseInt($(el).val());
        }
      });

      $(".sum-" + className).text(sumTotal);

      if (sumTotal > 100) {
        $(".sum-" + className).append("<div class='error'>cannot be greater than 100</div>");
      }

      tmp['sum_'+className] = sumTotal;

    }

  });
<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.3/jquery.min.js"></script>

<form action="test.php" method="post">
  <table>
    <tr>
      <td></td>
      <td></td>
      <td></td>
      <td></td>
      <td>Total</td>
    </tr>
    <tr>
      <td></td>
      <td>
        <input type="number" class="sum 1 5" min="0" max="100">
      </td>
      <td>
        <input type="number" class="sum 1 6" min="0" max="100">
      </td>
      <td>
        <input type="number" class="sum 1 7" min="0" max="100">
      </td>
      <td class="total sum-1"></td>
    </tr>
    <tr>
      <td></td>
      <td>
        <input type="number" class="sum 2 5" min="0" max="100">
      </td>
      <td>
        <input type="number" class="sum 2 6" min="0" max="100">
      </td>
      <td>
        <input type="number" class="sum 2 7" min="0" max="100">
      </td>
      <td class="total sum-2"></td>
    </tr>
    <tr>
      <td>TOTAL</td>
      <td class="total sum-5"></td>
      <td class="total sum-6"></td>
      <td class="total sum-7"></td>
    </tr>
  </table>
  <input type="submit" name="save" value="SAVE" id="btn-save"/>



回答3:

you will change the old condition by this:

if( tmp['sum_1'] == 100 && 
          tmp['sum_2'] == 100 && 
          tmp['sum_5'] <= 100 && 
          tmp['sum_6'] <= 100 && 
          tmp['sum_7'] <= 100) {
          enableSave();
} else {
        disableSave();
}


回答4:

my code looks dirty, but i just want you to know what exactly i did in each line.

btw, you can try this

$(function(){
	$('.btn-create').click(function(){
		var col = parseInt($('.count-column').val());
		var row = parseInt($('.count-row').val());
		
		$('table').html('');
		
		var head='<thead><tr><th></th>';
		var foot='<tfoot><tr><th>TOTAL ROW</th>';
		var tr = '';
		for(a=0; a< row;a++){
			tr += '<tr><td>row '+a+'</td>';
			for(b=0; b< col;b++){
				tr +='<td><input type="number" class="sum error-row" data-row="'+a+'" data-col="'+b+'" min="0" value="0" max="100"></td>';//all must have error row to prevent 0 0 0 0
				if(a==0) {foot +='<th class="total sumcol-'+b+'">0</th>';
				head +='<th>col '+b+'</th>';}
			}
			tr +='<td class="total sumrow-'+a+'">0</td>';
			tr +='</tr>';
			
			
		}
		head +='<th>TOTAL COL</th></tr></thead>';
		foot +='<th class=""><input type="submit" name="save" value="SAVE" disabled id="btn-save"/></th></tr></tfoot>';
		$('table').append(head+tr+foot);
		$('#btn-save').prop('disabled', true);
	});
	
	$("body").on('click', 'input[type="number"]',function () {
	   $(this).select();
	});
	
	$('.btn-show').click(function(){
		console.log($('table').html());
	})
	
	$("table").on("change", '.sum', function() {
		var val = parseInt($(this).val());
		if(isNaN(val)) val= 0;
		$(this).val(val); //parse int here, so you dont need parse all of them again
		var col = $(this).data('col');
		var row = $(this).data('row');
		
		//count row
		var rows = $('.sum[data-row="'+row+'"]');
		var total = 0;
		$.each(rows, function(i,e){
			total += parseInt($(this).val());
		});
		$('.sumrow-'+row).text(total);
		if(total == 100)  rows.removeClass('error-row');
		else{
			rows.addClass('error-row');	
		}
		
		//count col
		var cols = $('.sum[data-col="'+col+'"]');
		var total = 0;
		$.each(cols, function(i,e){
			total += parseInt($(this).val());
		});
		$('.sumcol-'+col).text(total);
		if(total <= 100)  cols.removeClass('error-col');
		else{
			cols.addClass('error-col');	
		}
		
		validate();
	});
	
	function validate(){
		if($('.error-col, .error-row').length > 0) $('#btn-save').prop('disabled', true);
		else $('#btn-save').prop('disabled', false);
	}
	
});
.error-row, .error-col{border: 1px solid red;}
table tfoot tr th:not(:first-child){font-weight: 400;}
how many rows x column <input type="number" min="1" value="2" class="count-row"> X <input min="1" value="3" type="number" class="count-column"> <button class="btn-create">create</button> <button class="btn-show">show DOM</button>
<form action="test.php" method="post">
<table></table>
</form>


<script src="https://code.jquery.com/jquery-3.1.0.js"></script>



回答5:

In this demo HTMLFormControlsCollection was used because it makes dealing with form controls easier with it's terse compact syntax. Added <output> tags to each total cells. All <input>s and <output>s have an id that's associated with it's cell (<td>).

Details are commented in Demo

Demo

/* Using old school HTMLFormControlsCollection */

// Reference the first (and only) form */
var f0 = document.forms[0];

// Collection of ALL form controls of f0
var F = f0.elements;

/* Handle any input events on f0 by calling 
|| callback function tableCalc()
*/
f0.oninput = tableCalc;

function tableCalc(e) {

  /* if the element receiving any user input (e.target)
  || is NOT the element that listens for input event
  || (e.currentTarget or f0) then...
  */
  if (e.target !== e.currentTarget) {

    /* Get e.target's id and determine the associated
    || outputs by e.target's id.
    */ // Example for <input id='r1c2'>
    // 'r1c2'
    var RC = e.target.id;
    // '1'
    var row = RC.charAt(1);
    // '2'
    var col = RC.charAt(3);
    // 'R1'
    var R = 'R' + row;
    // 'C2'
    var C = 'C' + col;

    /* Calculate the sums for each row */
    F[R].value = F['r' + row + 'c0'].valueAsNumber + F['r' + row + 'c1'].valueAsNumber + F['r' + row + 'c2'].valueAsNumber;

    /* Calculate the sums for each col */
    F[C].value = F['r0c' + col].valueAsNumber + F['r1c' + col].valueAsNumber;
  }

  /* if both rows === 100 AND none of the col exceed 100
  || enable the button
  */
  if (Number(F.R0.value) === 100 && Number(F.R1.value) === 100 && Number(F.C0.value) < 101 && Number(F.C1.value < 101) && Number(F.C2.value) < 101) {
    F.b0.disabled = false;

    // Otherwise the button is disabled
  } else {
    F.b0.disabled = true;
  }

  /* Collect all output tags into a NodeList then 
  || convert it into an array
  */
  var totals = Array.from(document.querySelectorAll('output'));

  // Run totals array through map() on each output...
  totals.map(function(out, idx, totals) {

    /* Get the associated error cell by matching
    || output.id to td.className
    */
    var msg = document.querySelector('.' + out.id);

    // Get output's value
    var val = Number(out.value);

    // if it exceeds 100...
    if (val > 100) {

      // Display message in associated error cell
      msg.textContent = `Exceeds 100`;
      out.style.color = 'red';
      out.style.textAlign = 'center';

      // Otherwise clear the error
    } else {
      msg.textContent = '';
      out.style.color = 'black';
      out.style.textAlign = 'right';
    }
  });
}
input,
output {
  display: inline-block;
  font: inherit;
  text-align: right
}

output {
  width: 7ch
}

button {
  font: inherit
}

td {
  max-width: 8ch;
}

.error {
  color: red;
  text-align: center
}
<form id='F0'>
  <table id='T0'>
    <thead>
      <tr>
        <th>C0</th>
        <th>C1</th>
        <th>C2</th>
        <th>Total</th>
        <th></th>
      </tr>
    </thead>
    <tbody>
      <tr>
        <td>
          <input id='r0c0' type='number' min='0' max='100' value='0'>
        </td>
        <td>
          <input id='r0c1' type='number' min='0' max='100' value='0'>
        </td>
        <td>
          <input id='r0c2' type='number' min='0' max='100' value='0'>
        </td>
        <td>
          <!--Row 1 total-->
          <output id='R0' for='r0c0 r0c1 r0c2'>0</output>
        </td>
        <!--Row 1 error cell-->
        <td class='R0 error' style='max-width:12ch'></td>
      </tr>
      <tr>
        <td>
          <input id='r1c0' type='number' min='0' max='100' value='0'>
        </td>
        <td>
          <input id='r1c1' type='number' min='0' max='100' value='0'>
        </td>
        <td>
          <input id='r1c2' type='number' min='0' max='100' value='0'>
        </td>
        <td>
          <!--Row 2 total-->
          <output id='R1' for='r1c0 r1c1 r1c2'>0</output>
        </td>
        <!--Row 2 error cell-->
        <td class='R1 error' style='max-width:12ch'></td>
      </tr>
      <tr>
        <td>
          <!--Column totals-->
          <output id='C0' for='r0c0 r1c0'>0</output>
        </td>
        <td>
          <output id='C1' for='r0c1 r1c1'>0</output>
        </td>
        <td>
          <output id='C2' for='r0c2 r1c2'>0</output>
        </td>
        <td>
          <!--Placed button here so it doesn't shift-->
          <button id='b0' disabled>SAVE</button>
        </td>
      </tr>
    </tbody>
    <tfoot>
      <tr>
        <!--Error cells for column totals-->
        <td class='C0 error'></td>
        <td class='C1 error'></td>
        <td class='C2 error'></td>
        <td></td>
        <td></td>
      </tr>
    </tfoot>
  </table>
</form>