1

Working on a storage website, I have to append jquery to create a new div section which is same as the first part of div, and so with them a unique identifier in the class and data attribute. I'm trying to call the keyin and undo button that is a unique identity to each newly created div.

I've tried adding the below before the click function, but the result comes back as data item 1 and won't go beyond.

var number = $('.product-item').data('item');

$(document).ready(function() {
 function ctrlSerial() {
  var number = $('.product-item').data('item');
  $('.keyin_ctrl_' + number).on('click', function() {
   var item = $(this).data('item');
   var result = $('.serial_' + item).val() + '\n';
   $('.display_' + item).append(result);
   $('.serial_' + item).val('');
   $('.serial_' + item).focus();
  });

  $('.undo_ctrl_' + number).on('click', function() {
   var item = $(this).data('item');
   $('.display_' + item).html('');
  });
 }

 $('#add_product').on('click', function() {
  var itemNo = $('.product-item').length + 1;
  var product = '<div class="product-item" id="product-' +
   itemNo + '" data-item="' + itemNo + 
   '"><span>#' + itemNo + '</span><br><input class="form-control serial_' +
   itemNo + '" maxlength="25" placeholder="Key in Serial Number and hit button Key In">'
   + '<button class="btn btn-dark keyin_ctrl_' + itemNo + ' keyin_ctrl" data-item="' + 
   itemNo + '" type="button">Key In</button><button class="btn btn-dark undo_ctrl_' + 
   itemNo + ' undo_ctrl" data-item="' + itemNo + '" type="button">Del</button>' + 
   '<br><textarea class="form-control display_' + itemNo + 
   '" name="products[0][serialnumbers]" rows="5" style="resize: none;"' + 
   'placeholder="eg. SGH8484848" readonly></textarea></div>';
  $('#append').append(product);
  ctrlSerial();
 });
 ctrlSerial();
});
<script src="https://cdnjs.cloudflare.com/ajax/libs/jquery/3.3.1/jquery.min.js"></script>
<button type="button" id="add_product" class="btn btn-dark">
Add Product&nbsp;<i class="fas fa-plus-square"></i>
</button>
<hr>
<div id="append">
 <div class="product-item" id="product-1" data-item="1">
  <span>#1</span><br>
  <input class="form-control serial_1" maxlength="25" 
placeholder="Key in Serial Number and hit button Key In">

  <button class="btn btn-dark keyin_ctrl_1 keyin_ctrl" 
       data-item="1" type="button">key in</button>
  <button class="btn btn-dark undo_ctrl_1 undo_ctrl" 
       data-item="1" type="button">del</button>
   <br>
   <textarea class="form-control display_1" name="products[0][serialnumbers]" rows="5"
 style="resize: none;" placeholder="eg. SGH8484848" readonly></textarea>
 </div>
</div>

jsFiddle

I am supposed to be able to key in on the 2nd added product.

Reporter
  • 3,547
  • 5
  • 28
  • 45
Kuwo
  • 53
  • 5
  • Possible duplicate of [Event binding on dynamically created elements?](https://stackoverflow.com/questions/203198/event-binding-on-dynamically-created-elements) – Roy Bogado Jul 15 '19 at 09:21

1 Answers1

2

The main issue with your logic is because you're only ever reading the first .product-item data attribute when the page loads. When subsequent ones are appended to the page their values are ignored. You can fix that by reading the new value from the appended content.

However it's worth noting that you can massively improve your logic. Currently your code is reliant on using the index that's appended to various id and class attributes, and is very brittle because of it. You can remove the reliance on this index and also make the code far more extensible by using common classes only along with DOM traversal to relate elements to each other. Try this:

$(document).ready(function() {
  let $append = $('#append');

  $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();
  });

  $append.on('click', '.undo_ctrl', function() {
    let $container = $(this).closest('.product-item');
    $container.find('.display').val('');
  });

  $('#add_product').on('click', function() {
    var itemNo = $('.product-item').length + 1;
    var $product = $append.find('.product-item:first').clone();
    $product.find('span').text('#' + itemNo);
    $('#append').append($product);
  });
});
textarea.display {
  resize: none;
}
<script src="https://cdnjs.cloudflare.com/ajax/libs/jquery/3.3.1/jquery.min.js"></script>
<button type="button" id="add_product" class="btn btn-dark">
  Add Product <i class="fas fa-plus-square"></i>
</button>
<hr />
<div id="append">
  <div class="product-item">
    <span>#1</span><br />
    <input class="form-control serial" maxlength="25" 
           placeholder="Key in Serial Number and hit button Key In">

    <button class="btn btn-dark keyin_ctrl keyin_ctrl" type="button">key in</button>
    <button class="btn btn-dark undo_ctrl undo_ctrl" type="button">del</button><br />
    <textarea class="form-control display" name="products[0][serialnumbers]" rows="5" 
             placeholder="eg. SGH8484848" readonly></textarea>
  </div>
</div>

Note in this example the use of delegated event handlers to cater for buttons which are dynamically appended to the page after load, and als the use of clone() instead of creating several lines of HTML in your JS code which is not a good separation of concerns.

Reporter
  • 3,547
  • 5
  • 28
  • 45
Rory McCrossan
  • 306,214
  • 37
  • 269
  • 303
  • @reporter the horizontal scrollbar is still there due to the ` – Rory McCrossan Jul 15 '19 at 09:37
  • When I reduce the width of my browser to smaller than 1024 pixels the horizontal scroll bar appears again due to the script tag. Removing the horizontal scrollbar improves the readbility quite much, because the div size is limited. ;-) – Reporter Jul 15 '19 at 10:34
  • 1
    Thank you @RoryMcCrossan very much, this clone is new to me, and i've dabble the code yesterday and learn a lot can be done with it. cheers! – Kuwo Jul 16 '19 at 02:12