因此,我拼凑了要用于创建发票的脚本。它将“发票项目”添加为表格行,其中包括复选框,数量,项目,单位成本和价格。
然后可以检查项目,或使用全选选项(左上)删除行。不仅如此,它还会自动计算整个“发票”的行总计以及子总计。只要您保持线性,就可以随意添加项目而不删除它们(除非删除所有项目),这样就可以很好地进行工作。我遇到的问题是,如果您删除中间的任何项目,它将不再计算总数。
这是我的第一篇文章,任何帮助将不胜感激-预先感谢!
<INPUT type="button" value="Add Invoice Item" onclick="addRow('dataTable')" />
<INPUT type="button" value="Delete Item(s)" onclick="deleteRow('dataTable')" />
<form action="" method="post" enctype="multipart/form-data">
<TABLE id="dataTable" width="350px" border="1" style="border-collapse:collapse;">
<TR>
<TH>
<INPUT type="checkbox" name="select-all" id="select-all" onclick="toggle(this);">
</TH>
<TH>Quanity</TH>
<TH>Item</TH>
<TH>Unit Cost</TH>
<TH formula="cost*qty" summary="sum">Price</TH>
</TR>
<TR>
<TD>
<INPUT type="checkbox" name="chk[]">
</TD>
<TD>
<INPUT type="text" id="qty1" name="qty[]" onchange="totalIt()"> </TD>
<TD>
<INPUT type="text" id="item1" name="item[]"> </TD>
<TD>
<INPUT type="text" id="cost1" name="cost[]" onchange="totalIt()"> </TD>
<TD>
<INPUT type="text" id="price1" name="price[]" readonly="readonly" value="0.00"> </TD>
</TR>
</TABLE>
</form>
Sub Total: <input type="text" readonly="readonly" id="total"><br><input type="submit" value="Create Invoice">
<!-------JAVASCRIPT--------->
<script>
function calc(idx) {
var price = parseFloat(document.getElementById("cost" + idx).value) *
parseFloat(document.getElementById("qty" + idx).value);
//alert(idx+":"+price);
document.getElementById("price" + idx).value = isNaN(price) ? "0.00" : price.toFixed(2);
//document.getElementById("total") = totalIt;
}
function totalIt() {
var qtys = document.getElementsByName("qty[]");
var total = 0;
for (var i = 1; i <= qtys.length; i++) {
calc(i);
var price = parseFloat(document.getElementById("price" + i).value);
total += isNaN(price) ? 0 : price;
}
document.getElementById("total").value = isNaN(total) ? "0.00" : total.toFixed(2);
}
window.onload = function() {
document.getElementsByName("qty[]")[0].onkeyup = function() {
calc(1)
};
document.getElementsByName("cost[]")[0].onkeyup = function() {
calc(1)
};
}
var rowCount = 0;
function addRow(tableID) {
var table = document.getElementById(tableID);
var rowCount = table.rows.length;
var row = table.insertRow(rowCount);
var cell1 = row.insertCell(0);
var element1 = document.createElement("input");
element1.type = "checkbox";
element1.name = "chk[]";
cell1.appendChild(element1);
var cell3 = row.insertCell(1);
var element3 = document.createElement("input");
element3.type = "text";
element3.name = "qty[]";
element3.id = "qty" + rowCount;
element3.onkeyup = totalIt;
cell3.appendChild(element3);
var cell4 = row.insertCell(2);
var element4 = document.createElement("input");
element4.type = "text";
element4.name = "item[]";
element4.id = "item" + rowCount;
cell4.appendChild(element4);
var cell5 = row.insertCell(3);
var element5 = document.createElement("input");
element5.type = "text";
element5.name = "cost[]";
element5.id = "cost" + rowCount;
element5.onkeyup = totalIt;
cell5.appendChild(element5);
var cell6 = row.insertCell(4);
var element6 = document.createElement("input");
element6.type = "text";
element6.name = "price[]";
element6.id = "price" + rowCount;
element6.value = "0.00";
$(element6).attr("readonly", "true");
cell6.appendChild(element6);
}
function deleteRow(tableID) {
try {
var table = document.getElementById(tableID);
var rowCount = table.rows.length;
document.getElementById("select-all").checked = false;
for (var i = 1; i < rowCount; i++) {
var row = table.rows[i];
var chkbox = row.cells[0].childNodes[0];
if (null != chkbox && true == chkbox.checked) {
table.deleteRow(i);
rowCount--;
i--;
}
}
} catch (e) {
alert(e);
}
}
</script>
<script type="text/javascript" src="//ajax.googleapis.com/ajax/libs/jquery/1.7.1/jquery.js"></script>
<script>
$("input").blur(function() {
if ($(this).attr("data-selected-all")) {
//Remove atribute to allow select all again on focus
$(this).removeAttr("data-selected-all");
}
});
$("input").click(function() {
if (!$(this).attr("data-selected-all")) {
try {
$(this).selectionStart = 0;
$(this).selectionEnd = $(this).value.length + 1;
//add atribute allowing normal selecting post focus
$(this).attr("data-selected-all", true);
} catch (err) {
$(this).select();
//add atribute allowing normal selecting post focus
$(this).attr("data-selected-all", true);
}
}
});
function toggle(source) {
var checkboxes = document.querySelectorAll('input[type="checkbox"]');
for (var i = 0; i < checkboxes.length; i++) {
if (checkboxes[i] != source)
checkboxes[i].checked = source.checked;
}
}
</script>
答案 0 :(得分:1)
由于当前代码已绑定到html中使用的索引(例如,诸如“ cost1”,“ price1”之类的ID),因此删除了中间的一行后会发生错误。
调用totalIt
函数时,它将尝试访问已删除的行。要解决此问题,您可以使用更广泛的选择器从特定索引中抽象出来。以下是不依赖索引的替换totalIt
函数的下落:
function totalIt() {
var costs = document.getElementsByName("cost[]");
var quantities = document.getElementsByName("qty[]");
var prices = document.getElementsByName("price[]");
var total = Array.prototype.reduce.call(costs, function(total, cost, index) {
var price = parseFloat(cost.value) * parseFloat(quantities[index].value);
prices[index].value = isNaN(price) ? "0.00" : price.toFixed(2);
return isNaN(price) ? total : total + price;
}, 0)
document.getElementById("total").value = isNaN(total) ? "0.00" : total.toFixed(2);
}
此外,是否要重新计算行删除总数-在删除处理程序(totalIt
)中调用deleteRow
。请注意,您可能需要将其包装在setTimeout
中,以便在实际从DOM中删除记录之后,在下一个事件循环迭代中进行重新计算