JSFiddle - React, Tailwind, and code Playground

by shojikun

HTML

<button type="button" id="add_product" class="btn btn-dark">
    Add Product&nbsp;
    <i class="fas fa-plus-square"></i></button>
<button type="button" id="delete_product" class="btn btn-dark ml-3">
    Delete Last Product&nbsp;
    <i class="fas fa-minus-square"></i></button>
<!-- Frist Group -->
<div class="product" id="append">
    <!-- Product Details -->
    <div class="product-item template" id="product">
        <span>#1</span>
        <div class="form-group row">
        <label class="col-sm-2 col-form-label font-weight-bold">Description</label>
        <div class="col-sm-8">
          <input class="form-control" name="products[0]description" type="text" placeholder="eg. Spare part for CSD2002">
        </div>
      </div>
        <div class="form-group row">
            <label class="col-sm-2 col-form-label font-weight-bold">Serial Number(s)</label>
            <div class="col-sm-5">
                <input class="form-control enable serial" maxlength="25"
                    placeholder="Key in Serial Number and hit button 'Key In'" disabled>
            </div>
            <div class="col-sm-5">
                <button class="btn btn-dark enable keyin-ctrl" type="button" disabled>Key In</button>
                <button class="btn btn-dark enable undo-ctrl" type="button" disabled>Del</button>
                <input class="form-check-input ml-4 mt-2 pointer enable-serial" id="checkbox[0]" type="checkbox">
                <label class="form-check-label ml-5 pointer"
                    for="checkbox[0]">tick to enable serialnumber</label>
            </div>
        </div>
        <div class="form-group row">
            <label class="col-sm-2 col-form-label"></label>
            <div class="col-sm-5">
                <textarea class="form-control display" name="products[0]serialnumbers" rows="5" style="resize: none;"
                    placeholder="eg. SGH8484848" readonly></textarea>
            </div>
        </div>
        <hr>
    </div>
    <!--...

JavaScript

$(document).ready(function() {

  let $append = $('#append');

  // enable checkbox for serialnumbers
  $append.on('change', '.enable-serial', function() {
    let $item = $(this).closest('.product-item');
    let $checkbox = $item.find('.enable');
    $checkbox.prop('disabled', !this.checked);
  });
  // ctrl for key in checkbox
  $append.on('click', '.keyin-ctrl', function() {
    let $container = $(this).closest('.product-item');
    let $serial = $container.find('.serial');
    $container.find('.display').val(function(i, v) {
      return v + $serial.val() + ';\n';
    });
    $serial.val('').focus();
  });
  // ctrl for del textarea
  $append.on('click', '.undo-ctrl', function() {
    let $container = $(this).closest('.product-item');
    $container.find('.display').val('');
  });
  // clone product, increment products[x]var
  $('#add_product').on('click', function() {
    var itemNo = $('.product-item').length + 1;
    var start = $('.product-item').length;
    let $product = $append.find('.product-item.template')
      .clone()
      .show()
      .removeClass('template')
      .insertAfter('.product-item:last');
    $product.find('span').text('#' + itemNo);
    $product.find('textarea').val('');
    $product.find(':checkbox').prop('checked', false);
    $product.find('.enable').prop('disabled', true);
    $product.find('input').each(function(){
      $(this).attr('name', $(this).attr('name').replace(/\d+/g, start));
      $(this).attr('id', $(this).attr('id').replace(/\d+/g, itemNo));
      $(this).val('');
    });
    $product.find('textarea').each(function(){
      $(this).attr('name', $(this).attr('name').replace(/\d+/g, itemNo));
      $(this).val('');
    })
    $product.find('label').attr('for', $(this).attr('for').replace(/\d+/g, itemNo));
    $('#append').append($product);
  });
  // delete product, but remain original template intact
  $('#delete_product').on('click', function() {
    var itemNo = $('.product-item').length + 1;
    let $product =...