首页 > 解决方案 > 使用 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>

例子 这些是发票项目输入

收据 收据生成

标签: javascripthtmljquery

解决方案


您可以将整个计算部分放在单独的函数中,并在需要时调用它。在此函数中,您可以使用.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>


推荐阅读