Kuwo
Kuwo

Reputation: 53

Trying to get parent data id for child on click with Jquery

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.

Upvotes: 1

Views: 1354

Answers (1)

Rory McCrossan
Rory McCrossan

Reputation: 337590

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.

Upvotes: 2

Related Questions