JavaScript, добавить HTML и ссылочные идентификаторы в функции

#javascript #html #jquery #function

#javascript #HTML #jquery #функция

Вопрос:

У меня есть форма, которая показывает выпадающее меню и текстовое поле рядом с ним:

 <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_value2 и test_calc2 , а затем добавил это ниже:

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

Я бы ожидал, что результат (по крайней мере, для одной новой добавленной строки) будет отображаться так же, как и для первой строки, но, похоже, ничего не происходит. Моя цель — получить результаты для добавленной строки, а затем также найти способ заставить эту функцию вычисления ввода работать для любого количества добавленных строк (а не жестко закодированных значений 2, 3, 4 и т.д.).

ids Я думаю, что их нужно будет динамически назначать по мере добавления строк, а затем name они останутся неизменными для хранения массивов для test_array и test_value , которые я собираюсь получать и обрабатывать через PHP.

Спасибо!

Комментарии:

1. Что это за ввод type="type" ? Вы имеете в виду type="number" ?

2. @RokoC. Булджан упс, спасибо, я набирал это слишком быстро и имел в виду «текст», но просто дважды набрал «тип». Это определенно может быть и «число», поскольку я ожидаю чисел, но я не хочу показывать стрелки, которые появляются в текстовом поле.

Ответ №1:

  • Удалите все свои идентификаторы из строк шаблона, используйте классы или name="" вместо этого в качестве селекторов
  • Присвойте идентификатор вашему TBODY, мы будем использовать его в качестве делегатора .on() событий
  • Используйте "input" событие, а не "keydown" событие. Вы также можете копировать / вставлять значения, помните?
  • на "input" — обратитесь к родительскому TR с помощью .closest() перед спуском назад (с помощью .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>  

Комментарии:

1. Это отлично, спасибо! Во-первых, для решения проблемы, а затем также советы и причины для них были очень полезны для улучшения моих знаний и навыков. Мне особенно нравится, как вы очистили мой HTML, чтобы выпадающее меню и текстовое поле не дублировались.

Ответ №2:

Идентификаторы должны быть уникальными, вместо этого всякий раз, когда вы добавляете другую строку, вы дублируете идентификаторы.

Вместо идентификаторов я изменил их на class, чтобы объединить это ключевое слово с .closest() и .find(), чтобы получить интересующие значения.

Более того, поскольку вы добавляете новые элементы в таблицу, вам нужно делегировать событие.

Если вы измените выбор, вам нужно будет вычислить снова, а не только при вводе в поле ввода.

 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>  

Комментарии:

1. Также спасибо за ваш отличный ответ! И я ценю, что вы предоставляете ссылки на соответствующие концепции.