javascript - 使用 jQuery 从动态输入中制作收据
问题描述
如何将发票项目描述和金额放入底部的收据中(与到期日相同),这有多个动态行输入,也可以删除。
我正在考虑启动一个计数器,在添加每一行之后它会增加计数器,不知道这是否是最好的方法
var generalPreset = [{
description: "This is item 1",
amount: "30.00"
}, {
description: "This is item 2",
amount: "45.00"
}];
var discountPresets = [{
description: "Siblings discount"
}, {
description: "Annual relief"
}];
// receipt
var receipt = new Object();
$('#duedate').change(function() {
receipt.duedate = $(this).val();
$('.invoice-preview-card-duedate-value').text(receipt.duedate);
});
// for adding invoice item
$('.add-invoice-item').click(function() {
$('.inv-table-body').append(`<div class="body-row row m-0">
<div class="px-2 col-3">
<select name="item_type[]" class="form-control invoiceType" required>
<option value="newitem">New Item</option>
<option value="presetitem">Present Item</option>
<option value="discount">Discount</option>
<option value="subsidy">Subsidy</option>
</select>
</div>
<div class="px-2 col-6 item-description" style="display: flex;">
<input type="text" class="form-control" name="description[]" placeholder="Add Invoice Description" required style="flex: 1">
</div>
<div class="px-2 col-2">
<input type="number" class="form-control invoiceItemAmount" name="amount[]" value="" placeholder="0" required>
</div>
<div class="col-1 del-icon-container"><button class="del-invoice-item">Del</button></div>
</div>
`);
});
// for deleting invoice item
$(document).on('click', '.del-invoice-item', function() {
$(this).closest('.body-row').remove();
});
// for description of invoice type change
$(document).on('change', '.invoiceType', function() {
let $field = $(this);
let invoiceType = $field.val(); // :selected not needed
if (invoiceType === 'newitem') {
$field.closest('.body-row').find('.item-description').html(`<input type="text" class="form-control" name="description[]" placeholder="Add Invoice Description" required style="flex: 1">`);
} else if (invoiceType === 'presetitem') {
var options;
$.each(generalPreset, function(key, value) {
options = options + '<option value="' + value.amount + '">' + value.description + '</option>';
});
$field.closest('.body-row').find('.item-description').html(`
<select class="form-control general-presets" name="description[]" required style="flex: 1">
<option></option>
` +
options +
`
</select>
`);
} else if (invoiceType === 'discount') {
var dicountOptions;
$.each(discountPresets, function(key, value) {
dicountOptions = dicountOptions + '<option>' + value.description + '</option>';
});
$field.closest('.body-row').find('.item-description').html(`<div class="mr-2 divForCalculation" style="flex: 1">
<div style="display: flex" class="calculation-container">
<div class="mr-2" style="flex: 1">
<div class="input-group my-group">
<input type="text" class="form-control discountAmount" name="snpid" placeholder="0">
<select id="lunch" class="form-control amountOrPercent" style="padding: 4px;">
<option value="amount">$</option>
<option value="percentage">%</option>
</select>
</div>
</div>
</div>
</div>
<select class="form-control discount-presets" name="description[]" required style="flex: 2">
<option></option>
` +
dicountOptions +
`
</select>
`);
} else if (invoiceType === 'subsidy') {
$field.closest('.body-row').find('.item-description').html(`<div class="mr-2 divForCalculation" style="flex: 1">
<div style="display: flex" class="calculation-container">
<div class="mr-2" style="flex: 1">
<div class="input-group my-group">
<input type="text" class="form-control discountAmount" name="snpid" placeholder="0">
<select id="lunch" class="form-control amountOrPercent" style="padding: 4px;">
<option value="amount">$</option>
<option value="percentage">%</option>
</select>
</div>
</div>
</div>
</div>
<input type="text" class="form-control" name="description[]" placeholder="Add Invoice Description" required style="flex: 2">
`);
}
});
// populate invoice amount by preset items
$(document).on('change', '.general-presets', function() {
var presetSelectValue = $(this).find(":selected").val();
$(this).closest(".body-row").find(".invoiceItemAmount").val(presetSelectValue);
});
// Percentage or Amount structure change
$(document).on('change', '.amountOrPercent', function() {
var amountOrPercent = $(this).find(":selected").val();
if (amountOrPercent == 'amount') {
$(this).closest('.body-row').find('.extraForPercentage').remove();
$(this).closest('.body-row').find('.amountOrPercent').css('padding', '4px');
$(this).closest('.body-row').find('.divForCalculation').css('flex', '1');
} else if (amountOrPercent == 'percentage') {
$(this).closest('.body-row').find('.divForCalculation').css('flex', '2');
$(this).closest('.body-row').find('.amountOrPercent').css('padding', '0');
$(this).closest('.body-row').find('.calculation-container').append(`<div class="extraForPercentage" style="flex: 1">
<span class="mr-2 pt-2">Of</span>
<div style="display: inline;">
<input type="text" class="form-control totalof" placeholder="0" required style="display: inline; width: 60%;" value="">
</div>
</div>
`);
}
});
$(document).on("change keyup keypress", ".discountAmount, .totalof , .amountOrPercent", function() {
var selector = $(this).closest(".divForCalculation") //get closest div
var discountAmount = 0;
var discountPercentage = 0;
var totalof = 0;
var result = 0;
discountAmount = selector.find(".discountAmount").val();
totalof = selector.find(".totalof").val();
//added cond if not visible
if (totalof == null || totalof == 0 || !selector.find(".totalof").is(":visible")) {
totalof = 0;
//change value depending on select values
result = selector.find(".amountOrPercent").val() == "amount" ? -discountAmount : 0;
} else {
result = -parseFloat((parseInt(totalof) / 100 * parseInt(discountAmount)));
}
//use nextAll..
// selector.nextAll('.invoiceItemAmount').val(result);
$(this).closest(".body-row").find(".invoiceItemAmount").val(result);
});
.invoice-preview-card-header {
padding: 44px 24px;
}
.invoice-preview-card-body {
padding: 18px 24px;
background-color: #ebf2ef;
}
.invoice-preview-card-duedate-value {
font-weight: bold;
}
.invoice-preview-card-table {
margin-top: 12px;
}
.invoice-preview-card-table-header {
padding: 10px 0;
border-bottom: 1px solid #d8d8d8
}
.invoice-preview-card-table-column1 {
width: 75%;
display: inline-block;
}
.invoice-preview-card-table-column2 {
width: 20%;
display: inline-block;
}
.invoice-preview-card-table-body {
border-bottom: 1px solid #d8d8d8;
}
.invoice-preview-card-table-row {
padding-top: 12px;
}
.invoice-preview-card-table-row:last-child {
padding-bottom: 12px;
}
.invoice-preview-card-table-body > .invoice-preview-card-table-row {
font-weight: bold;
}
.invoice-preview-card-table-column2 {
text-align: right;
}
.invoice-preview-card-table-footer {
padding: 10px 0;
}
.invoice-preview-card-table-footer > .invoice-preview-card-table-column2 {
font-weight: normal;
}
.invoice-preview-card-table-footer > .invoice-preview-card-table-column2 span{
font-weight: bold;
}
<link href="https://maxcdn.bootstrapcdn.com/bootstrap/4.0.0/css/bootstrap.min.css" rel="stylesheet" />
<script src="https://cdnjs.cloudflare.com/ajax/libs/jquery/3.3.1/jquery.min.js"></script>
<div class="form-card">
<div class="row">
<div class="form-group col-md-4">
<label for="">Invoice Due Date</label>
<input type="date" class="form-control" name="duedate" id="duedate"> </div>
<div class="form-group col-md-8">
<div class="row mr-0">
<label for="" class="col-12 pl-0">Date of Service(optional)</label>
<input type="date" class="form-control col" name="service_start" id="">
<span class="service-span">to</span>
<input type="date" class="form-control col" name="service_end" id="">
</div>
</div>
</div>
<hr>
<h5>Invoice Details</h5>
<div class="card" style="border: 1px solid #d8d8d8;">
<div class="inv-table">
<div class="inv-table-head">
<div class="head-row row m-0">
<div class="px-2 col-3">Row</div>
<div class="px-2 col-6">Description</div>
<div class="px-2 col-2">Amount</div>
<div class="px-2 col-1"></div>
</div>
</div>
<div class="inv-table-body">
<div class="body-row row m-0">
<div class="px-2 col-3">
<select name="invoice_type" class="form-control invoiceType" required>
<option value="newitem">New Item</option>
<option value="presetitem">Preset Item</option>
<option value="discount">Discount</option>
<option value="subsidy">Subsidy</option>
</select>
</div>
<div class="px-2 col-6 item-description" style="display: flex;">
<input type="text" class="form-control" name="description[]" placeholder="Add Invoice Description" required style="flex: 1">
</div>
<div class="px-2 col-2">
<input type="number" class="form-control invoiceItemAmount" name="amount[]" placeholder="0" value="" required>
</div>
<div class="col-1 del-icon-container"><i class="fas fa-trash"></i></div>
</div>
</div>
<div class="inv-table-footer">
<div class="row">
<div class="col-6">
<span class="add-invoice-item">
<i class="fas fa-plus-circle"></i> ADD INVOICE ITEM
</span>
</div>
<div class="col-6">
<span class="">
<b>Total: </b> $<span class="tatalAmountShow">0</span>
</span>
</div>
</div>
</div>
</div>
</div>
</div>
<br><br>
<hr>
<br>
<div class="invoice-preview-card-body">
<div class="invoice-preview-card-duedate">
Due Date: <span class="invoice-preview-card-duedate-value"></span>
</div>
<div class="invoice-preview-card-duedate">
Invoice Period: <span class="invoice-preview-card-duedate-value">May 1, 2021 - May 10, 2021</span>
</div>
<div class="invoice-preview-card-table">
<div class="invoice-preview-card-table-header">
<div class="invoice-preview-card-table-column1">
Description
</div>
<div class="invoice-preview-card-table-column2">
Amount
</div>
</div>
<div class="invoice-preview-card-table-body">
<div class="invoice-preview-card-table-row">
<div class="invoice-preview-card-table-column1">
This is item 1
</div>
<div class="invoice-preview-card-table-column2">
$30
</div>
</div>
<div class="invoice-preview-card-table-row">
<div class="invoice-preview-card-table-column1">
This is item 2
</div>
<div class="invoice-preview-card-table-column2">
$45
</div>
</div>
</div>
<div class="invoice-preview-card-table-footer">
<div class="invoice-preview-card-table-column1">
</div>
<div class="invoice-preview-card-table-column2">
Total <span>$0</span>
</div>
</div>
</div>
</div>
解决方案
您可以将整个计算部分放在单独的函数中,并在需要时调用它。在此函数中,您可以使用.each
循环进行迭代,body-row
然后在该 div 中获取值并将其传递给您的发票正文标签。
演示代码:
var generalPreset = [{
description: "This is item 1",
amount: "30.00"
}, {
description: "This is item 2",
amount: "45.00"
}];
var discountPresets = [{
description: "Siblings discount"
}, {
description: "Annual relief"
}];
// receipt
var receipt = new Object();
$('#duedate').change(function() {
receipt.duedate = $(this).val();
$('.invoice-preview-card-duedate-value').text(receipt.duedate);
});
// for adding invoice item
$('.add-invoice-item').click(function() {
$('.inv-table-body').append(`<div class="body-row row m-0">
<div class="px-2 col-3">
<select name="item_type[]" class="form-control invoiceType" required>
<option value="newitem">New Item</option>
<option value="presetitem">Present Item</option>
<option value="discount">Discount</option>
<option value="subsidy">Subsidy</option>
</select>
</div>
<div class="px-2 col-6 item-description" style="display: flex;">
<input type="text" class="form-control" name="description[]" placeholder="Add Invoice Description" required style="flex: 1">
</div>
<div class="px-2 col-2">
<input type="number" class="form-control invoiceItemAmount" name="amount[]" value="" placeholder="0" required>
</div>
<div class="col-1 del-icon-container"><button class="del-invoice-item">Del</button></div>
</div>
`);
});
// for deleting invoice item
$(document).on('click', '.del-invoice-item', function() {
$(this).closest('.body-row').remove();
build_invoice() //call this
});
// for description of invoice type change
$(document).on('change', '.invoiceType', function() {
let $field = $(this);
let invoiceType = $field.val(); // :selected not needed
if (invoiceType === 'newitem') {
$field.closest('.body-row').find('.item-description').html(`<input type="text" class="form-control" name="description[]" placeholder="Add Invoice Description" required style="flex: 1">`);
} else if (invoiceType === 'presetitem') {
var options;
$.each(generalPreset, function(key, value) {
options = options + '<option value="' + value.amount + '">' + value.description + '</option>';
});
$field.closest('.body-row').find('.item-description').html(`
<select class="form-control general-presets" name="description[]" required style="flex: 1">
<option></option>
` +
options +
`
</select>
`);
} else if (invoiceType === 'discount') {
var dicountOptions;
$.each(discountPresets, function(key, value) {
dicountOptions = dicountOptions + '<option>' + value.description + '</option>';
});
$field.closest('.body-row').find('.item-description').html(`<div class="mr-2 divForCalculation" style="flex: 1">
<div style="display: flex" class="calculation-container">
<div class="mr-2" style="flex: 1">
<div class="input-group my-group">
<input type="text" class="form-control discountAmount" name="snpid" placeholder="0">
<select id="lunch" class="form-control amountOrPercent" style="padding: 4px;">
<option value="amount">$</option>
<option value="percentage">%</option>
</select>
</div>
</div>
</div>
</div>
<select class="form-control discount-presets" name="description[]" required style="flex: 2">
<option></option>
` +
dicountOptions +
`
</select>
`);
} else if (invoiceType === 'subsidy') {
$field.closest('.body-row').find('.item-description').html(`<div class="mr-2 divForCalculation" style="flex: 1">
<div style="display: flex" class="calculation-container">
<div class="mr-2" style="flex: 1">
<div class="input-group my-group">
<input type="text" class="form-control discountAmount" name="snpid" placeholder="0">
<select id="lunch" class="form-control amountOrPercent" style="padding: 4px;">
<option value="amount">$</option>
<option value="percentage">%</option>
</select>
</div>
</div>
</div>
</div>
<input type="text" class="form-control" name="description[]" placeholder="Add Invoice Description" required style="flex: 2">
`);
}
});
// populate invoice amount by preset items
$(document).on('change', '.general-presets', function() {
var presetSelectValue = $(this).find(":selected").val();
$(this).closest(".body-row").find(".invoiceItemAmount").val(presetSelectValue);
build_invoice() //call this
});
// Percentage or Amount structure change
$(document).on('change', '.amountOrPercent', function() {
var amountOrPercent = $(this).find(":selected").val();
if (amountOrPercent == 'amount') {
$(this).closest('.body-row').find('.extraForPercentage').remove();
$(this).closest('.body-row').find('.amountOrPercent').css('padding', '4px');
$(this).closest('.body-row').find('.divForCalculation').css('flex', '1');
} else if (amountOrPercent == 'percentage') {
$(this).closest('.body-row').find('.divForCalculation').css('flex', '2');
$(this).closest('.body-row').find('.amountOrPercent').css('padding', '0');
$(this).closest('.body-row').find('.calculation-container').append(`<div class="extraForPercentage" style="flex: 1">
<span class="mr-2 pt-2">Of</span>
<div style="display: inline;">
<input type="text" class="form-control totalof" placeholder="0" required style="display: inline; width: 60%;" value="">
</div>
</div>
`);
}
});
$(document).on("change keyup keypress", ".discountAmount, .totalof , .amountOrPercent", function() {
var selector = $(this).closest(".divForCalculation") //get closest div
var discountAmount = 0;
var discountPercentage = 0;
var totalof = 0;
var result = 0;
discountAmount = selector.find(".discountAmount").val();
totalof = selector.find(".totalof").val();
//added cond if not visible
if (totalof == null || totalof == 0 || !selector.find(".totalof").is(":visible")) {
totalof = 0;
//change value depending on select values
result = selector.find(".amountOrPercent").val() == "amount" ? -discountAmount : 0;
} else {
result = -parseFloat((parseInt(totalof) / 100 * parseInt(discountAmount)));
}
//use nextAll..
// selector.nextAll('.invoiceItemAmount').val(result);
$(this).closest(".body-row").find(".invoiceItemAmount").val(result);
build_invoice() //call this
});
function build_invoice() {
$(".invoice-preview-card-table-body").html("")
var total = 0
console.clear()
//loop through body-row
$(".inv-table-body > .body-row").each(function() {
//because genral slect value="number" that's why text
var desc = $(this).find(".item-description [name*='description']").hasClass("general-presets") ? $(this).find(".item-description [name*='description']").find("option:selected").text() : $(this).find(".item-description [name*='description']").val();
//get amt
var amt = $(this).find(".invoiceItemAmount").val() != "" ? $(this).find(".invoiceItemAmount").val() : 0
//append in body
$(".invoice-preview-card-table-body").append(`<div class="invoice-preview-card-table-row">
<div class="invoice-preview-card-table-column1">
${desc}
</div>
<div class="invoice-preview-card-table-column2">
${amt}
</div>
</div>`)
total += parseFloat(amt) //for total
})
$("#to_inv").text("$" + total) //add total
}
.invoice-preview-card-header {
padding: 44px 24px;
}
.invoice-preview-card-body {
padding: 18px 24px;
background-color: #ebf2ef;
}
.invoice-preview-card-duedate-value {
font-weight: bold;
}
.invoice-preview-card-table {
margin-top: 12px;
}
.invoice-preview-card-table-header {
padding: 10px 0;
border-bottom: 1px solid #d8d8d8
}
.invoice-preview-card-table-column1 {
width: 75%;
display: inline-block;
}
.invoice-preview-card-table-column2 {
width: 20%;
display: inline-block;
}
.invoice-preview-card-table-body {
border-bottom: 1px solid #d8d8d8;
}
.invoice-preview-card-table-row {
padding-top: 12px;
}
.invoice-preview-card-table-row:last-child {
padding-bottom: 12px;
}
.invoice-preview-card-table-body>.invoice-preview-card-table-row {
font-weight: bold;
}
.invoice-preview-card-table-column2 {
text-align: right;
}
.invoice-preview-card-table-footer {
padding: 10px 0;
}
.invoice-preview-card-table-footer>.invoice-preview-card-table-column2 {
font-weight: normal;
}
.invoice-preview-card-table-footer>.invoice-preview-card-table-column2 span {
font-weight: bold;
}
<link href="https://maxcdn.bootstrapcdn.com/bootstrap/4.0.0/css/bootstrap.min.css" rel="stylesheet" />
<script src="https://cdnjs.cloudflare.com/ajax/libs/jquery/3.3.1/jquery.min.js"></script>
<div class="form-card">
<div class="row">
<div class="form-group col-md-4">
<label for="">Invoice Due Date</label>
<input type="date" class="form-control" name="duedate" id="duedate"> </div>
<div class="form-group col-md-8">
<div class="row mr-0">
<label for="" class="col-12 pl-0">Date of Service(optional)</label>
<input type="date" class="form-control col" name="service_start" id="">
<span class="service-span">to</span>
<input type="date" class="form-control col" name="service_end" id="">
</div>
</div>
</div>
<hr>
<h5>Invoice Details</h5>
<div class="card" style="border: 1px solid #d8d8d8;">
<div class="inv-table">
<div class="inv-table-head">
<div class="head-row row m-0">
<div class="px-2 col-3">Row</div>
<div class="px-2 col-6">Description</div>
<div class="px-2 col-2">Amount</div>
<div class="px-2 col-1"></div>
</div>
</div>
<div class="inv-table-body">
<div class="body-row row m-0">
<div class="px-2 col-3">
<select name="invoice_type" class="form-control invoiceType" required>
<option value="newitem">New Item</option>
<option value="presetitem">Preset Item</option>
<option value="discount">Discount</option>
<option value="subsidy">Subsidy</option>
</select>
</div>
<div class="px-2 col-6 item-description" style="display: flex;">
<input type="text" class="form-control" name="description[]" placeholder="Add Invoice Description" required style="flex: 1">
</div>
<div class="px-2 col-2">
<input type="number" class="form-control invoiceItemAmount" name="amount[]" placeholder="0" value="" required>
</div>
<div class="col-1 del-icon-container"><i class="fas fa-trash"></i></div>
</div>
</div>
<div class="inv-table-footer">
<div class="row">
<div class="col-6">
<span class="add-invoice-item">
<i class="fas fa-plus-circle"></i> ADD INVOICE ITEM
</span>
</div>
<div class="col-6">
<span class="">
<b>Total: </b> $<span class="tatalAmountShow">0</span>
</span>
</div>
</div>
</div>
</div>
</div>
</div>
<br><br>
<hr>
<br>
<div class="invoice-preview-card-body">
<div class="invoice-preview-card-duedate">
Due Date: <span class="invoice-preview-card-duedate-value"></span>
</div>
<div class="invoice-preview-card-duedate">
Invoice Period: <span class="invoice-preview-card-duedate-value">May 1, 2021 - May 10, 2021</span>
</div>
<div class="invoice-preview-card-table">
<div class="invoice-preview-card-table-header">
<div class="invoice-preview-card-table-column1">
Description
</div>
<div class="invoice-preview-card-table-column2">
Amount
</div>
</div>
<div class="invoice-preview-card-table-body">
</div>
<div class="invoice-preview-card-table-footer">
<div class="invoice-preview-card-table-column1">
</div>
<div class="invoice-preview-card-table-column2">
Total <span id="to_inv">$0</span>
</div>
</div>
</div>
</div>
推荐阅读
- java - Java泛型,如何正确地将孩子转换为方法?
- spring-boot - 弹簧工具套件 4 的 Gradle 6.5 问题
- regex - 雪花图案的正则表达式
- javascript - 如何在按钮上实现ajax
- javascript - Twitter API 销毁流
- c - 如何在 C 中实现指针?
- gcc - 当 Address Sanitizer 说此平台不支持 detect_leaks 时,我应该如何解决?
- reactjs - ReactJS 在我的天蓝色租户中注册
- javascript - 做什么
Adobe 扩展脚本中的关键字 - spinnaker - 开始新的执行时如何取消以前的“正在运行”的大三角帆执行