Trabajar en un sitio web de almacenamiento, tengo que agregar jquery para crear una nueva sección div que sea la misma que la primera parte de DIV, y así, con ellos un identificador único en la clase y el atributo de datos. Estoy tratando de llamar al botón Keyin y Deshacer que es una identidad única para cada DIV recién creado.

He intentado agregar los siguientes antes de la función de clic, pero el resultado regresa como elemento de datos 1 y no irá más allá.

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

Se supone que debo acceder al 2do producto agregado.

1
Kuwo 15 jul. 2019 a las 12:18

1 respuesta

La mejor respuesta

El problema principal con su lógica es porque solo está leyendo el primer atributo de datos .product-item cuando se carga la página. Cuando los posteriores se adjuntan a la página, sus valores se ignoran. Puede solucionarlo leyendo el nuevo valor del contenido adjunto.

Sin embargo, vale la pena señalar que puede mejorar masivamente su lógica. Actualmente, su código depende de usar el índice que se adjunta a varios atributos id y class, y es muy frágil debido a ella. Puede eliminar la confianza en este índice y también hacer que el código sea mucho más extensible usando clases comunes solo junto con DOM Traversal para relacionar los elementos entre sí. Prueba esto:

$(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>

NOTA En este ejemplo, el uso de los manipuladores del evento delegado para atender los botones que se adjuntan dinámicamente a la página después de la carga y la ALS el uso de clone() en lugar de crear varias líneas de HTML en su código JS, que no es un buen separación de intereses.

2
Reporter 15 jul. 2019 a las 09:33