JavaScript,在函数中附加HTML和参考ID

问题描述

我有一个显示下拉菜单并在其旁边的文本字段的表单:

<html>
<body>
<table>
  <tbody class="project_wrapper">
    <tr>
      <td scope="row">
      <select id="test_project" name="test_project[]">
        <option selected>Select</option>
        <option>10</option>
        <option>20</option>
      </select>
      </td>
      <td><input id="test_value" name="test_value[]" type="text" placeholder="Enter value"></td>
      <td><div id="test_calc"></div></td>
    </tr>
  </tbody>
  <tbody>
    <tr>
      <td colspan="3">
      <a href="javascript:void(0);" class="add_project" title="Add project">Add another project</a>
      </td>
    </tr>
  </tbody>
</table>
</body>
</html>

您可以在下拉列表中选择一个值,然后在文本字段中输入数字值时,每次键入时,它将显示该值乘以所选值。您还可以单击“添加一个项目”链接,它将附加/创建另一个下拉列表和文本字段。这已经有效,并且可以通过以下Jquery代码完成:

<script type="text/javascript">
$(document).ready(function(){
  var addProject = $('.add_project');
  var wrapper = $('.project_wrapper');
  var projectHTML = `<tr>
                       <td scope="row">
                       <select id="test_project2" name="test_project[]" class="custom-select">
                         <option selected>Select</option>
                         <option>10</option>
                         <option>20</option>
                       </select>
                       </td>
                       <td><input id="test_value2" name="test_value[]" type="text" placeholder="Enter value"></td>
                    <td><div id="test_calc2"></div></td>
                  </tr>`;

  $(addProject).click(function(){
    $(wrapper).append(projectHTML);
  });
});

$('#test_value').keyup(function(){
  $('#test_calc').text(Math.round($(this).val() * $("#test_project option:selected").val()));
});

问题是我无法使用乘法功能来工作/显示任何新添加的行的结果。在上方可以看到我尝试对test_value2test_calc2的值进行硬编码,然后在下面添加了它:

$('#test_value2').keyup(function(){
  $('#test_calc2').text(Math.round($(this).val() * $("#test_project2 option:selected").val()));
});

我希望结果(至少对于一个新的附加行)以与第一行相同的方式出现,但似乎什么也没有发生。我的目标是使结果显示在附加行中,然后找到一种方法,使keyup计算功能适用于任意数量的附加行(而不是硬编码2、3、4等值)。>

我认为,ids将在行添加时进行动态分配,然后name将保持不变,以容纳test_array和{{ 1}},我将通过PHP进行接收和处理。

谢谢!

解决方法

这些ID必须是唯一的,每当您添加另一行时,您都应该重复这些ID。

为了将 this 关键字与.closest().find()结合使用,我将其替换为ID,以获取感兴趣的值。

此外,由于您向表中添加了新元素,因此需要delegate事件。

如果更改选择,则不仅需要在输入字段中键入内容,还需要再次计算。

var addProject = $('.add_project');
var wrapper = $('.project_wrapper');
var projectHTML = '<tr>\
<td scope="row">\
        <select class="test_project" name="test_project[]" class="custom-select">\
        <option selected>Select</option>\
<option>10</option>\
<option>20</option>\
</select>\
</td>\
<td><input class="test_value" name="test_value[]" type="number" placeholder="Enter value"></td>\
        <td><div class="test_calc"></div></td>\
</tr>';

$(addProject).click(function () {
    $(wrapper).append(projectHTML);
});

$(document).on('input','.test_value',function (e) {
    $(this).closest('tr').find('.test_calc').text(Math.round($(this).val() * $(this).closest('tr').find('.test_project option:selected').val() || 0));
});

$(document).on('change','.test_project',function(e) {
  $(this).closest('tr').find('.test_value').trigger('input');
});
<script src="https://cdnjs.cloudflare.com/ajax/libs/jquery/3.3.1/jquery.min.js"></script>


<table>
    <tbody class="project_wrapper">
    <tr>
        <td scope="row">
            <select class="test_project" name="test_project[]">
                <option selected>Select</option>
                <option>10</option>
                <option>20</option>
            </select>
        </td>
        <td><input class="test_value" name="test_value[]" type="number" placeholder="Enter value"></td>
        <td>
            <div class="test_calc"></div>
        </td>
    </tr>
    </tbody>
    <tbody>
    <tr>
        <td colspan="3">
            <a href="javascript:void(0);" class="add_project" title="Add project">Add another project</a>
        </td>
    </tr>
    </tbody>
</table>

,
  • 从模板行中删除所有ID,使用类或name=""作为选择器
  • 为您的TBODY分配一个ID,我们将其用作.on()事件delegator
  • 使用"input"事件,而不是"keydown"事件。您还可以复制/粘贴值,记得吗?
  • "input"上-使用.closest()引用父TR,然后下移(使用.find())以查找特定于该行的元素
  • 使用parseInt()parseFloat()处理输入字符串。另外请记住,始终回退到一个数字,即:0以防止出现NaN结果

jQuery(function($) {

  const projectHTML = `<tr>
     <td>
       <select name="test_project[]" class="custom-select">
         <option value="" selected>Select</option>
         <option value="10">10</option>
         <option value="20">20</option>
       </select>
     </td>
     <td><input name="test_value[]" type="type" placeholder="Enter value"></td>
     <td><div class="result"></div></td>
  </tr>`;

  const $projects = $("#projects"); // assign an ID to your tbody
  const $addProject = $('.add_project');
  const arrRow = () => $projects.append(projectHTML);

  // Create new row on click
  $addProject.on("click",arrRow);
  
  // Add the first row
  arrRow(); 

  // use a delegator which is not dymanic (the TBODY in this case),// and use delegated events to any ":input" element:
  
  $projects.on("input",":input",function(ev) {
    const $tr = $(this).closest("tr");
    
    const $project = $tr.find('[name="test_project[]"]');
    const $value = $tr.find('[name="test_value[]"]');
    const $result = $tr.find(".result");
        
    const project = parseInt($project.val(),10) || 0;
    const value = parseFloat($value.val()) || 0;
    const result = project * value;
    
    $result.text(result);
  });

});
<table>
  <tbody id="projects"></tbody>
  <tbody>
    <tr>
      <td colspan="3">
        <a href="javascript:void(0);" class="add_project" title="Add project">Add another project</a>
      </td>
    </tr>
  </tbody>
</table>

<script src="https://cdnjs.cloudflare.com/ajax/libs/jquery/3.5.1/jquery.min.js"></script>