Цикл по элементам списка с помощью jQuery

61

У меня есть этот блок кода

listItems = $("#productList").find("li");

        for (var li in listItems) {
            var product = $(li);
            var productid = product.children(".productId").val();
            var productPrice = product.find(".productPrice").val();
            var productMSRP = product.find(".productMSRP").val();

            totalItemsHidden.val(parseInt(totalItemsHidden.val(), 10) + 1);
            subtotalHidden.val(parseFloat(subtotalHidden.val()) + parseFloat(productMSRP));
            savingsHidden.val(parseFloat(savingsHidden.val()) + parseFloat(productMSRP - productPrice));
            totalHidden.val(parseFloat(totalHidden.val()) + parseFloat(productPrice));

        }

и я не получаю желаемых результатов - totalItems выходит как 180+, а все остальное - NaN. Я подозреваю, что это то, где я использую, var product = $(li);или, возможно, с выражением в самом цикле. В любом случае - мне нужно перебрать <li>элементы в <ul>отмеченных#productList

4
  • Начинаются ли ваши "аккумуляторные" поля с пустых значений? Если да, то вот откуда берутся ваши NaNрезультаты.
    Pointy
    22 дек.
  • Причина, по которой вы получаете 180+ элементов, заключается в том, что a for/inвключает в себя свойства прототипа, а также свойства фактического экземпляра. Все методы jQuery, которые могут быть вызваны для объекта jQuery, являются частью прототипа объекта. Как вы теперь знаете, .each()это обычный, но не единственный способ повторения. 22 дек.
  • .each будет делать это. Рабочий пример jsfiddle.net/Lijo/Hb28u/16
    LCJ
    18 фев '13 в 18: 432013-02-18 15:43
  • Спасибо за ваш комментарий, но ответ был дан 2 года назад ... 19 фев '13 в 16: 092013-02-19 16:09
138

Вам нужно использовать .each:

var listItems = $("#productList li");
listItems.each(function(idx, li) {
    var product = $(li);

    // and the rest of your code
});

Это правильный способ пройти через выбор jQuery.


В современном Javascript вы также можете использовать for .. ofцикл:

var listItems = $("#productList li");
for (let li of listItems) {
    let product = $(li);
}

Однако имейте в виду, что старые браузеры не поддерживают этот синтаксис, и вам может быть лучше с синтаксисом jQuery, описанным выше.

4
  • 2
    просто чтобы добавить к этому, вы, вероятно, захотите также изменить свой селектор на $ ("# productList li"). Вместо использования find.
    Vadim
    22 дек.
  • @ Ядс Не обязательно. Я не знаю наверняка, но есть все шансы, что исходный код будет более эффективным во многих браузерах, поскольку он не требует столь интенсивного синтаксического анализа строки. 22 дек.
  • 4
    Хм, я сделал несколько быстрых тестов в jQuery 1.4.2. Использование метода find было примерно на 30% медленнее, чем совокупный селектор как в IE7, так и в Chrome.
    Vadim
    22 дек.
  • @Yads Достаточно честно - спасибо за информацию. Отредактирую свой ответ. 22 дек.
17

eachДля этого можно использовать :

$('#productList li').each(function(i, li) {
  var $product = $(li);  
  // your code goes here
});

При этом - вы уверены, что хотите обновлять значения до +1 каждый раз? Не могли бы вы просто найти счетчик и затем установить значения на его основе?

4
  • Нет необходимости передавать i и li в качестве аргументов? Возможно, мне что-то не хватает, но я думал, что объект, над которым выполняются действия, по умолчанию передан функции как объект this.
    exoboy
    22 дек.
  • Тем не менее, никогда не помешает быть откровенным - меня несколько раз слишком много укушало, когда я полагался на this. :) 22 дек.
  • @exoboy вы правы, но это также верно , что Jquery проходит в качестве аргументов элемент и индекс элемента в выбранном списке JQuery.
    Pointy
    22 дек.
  • 1
    @all: Вот почему мне нравится этот форум ... приятно видеть другие точки зрения и иногда узнавать что-то новое по пути.
    exoboy
    22 дек.
6

Попробуй это:

listItems = $("#productList").find("li").each(function(){
   var product = $(this);
   // rest of code.
});
2

Попробуйте этот код. Используя родительский> дочерний селектор "#productList li", он должен найти все элементы li. Затем вы можете перебирать объект результата, используя метод each (), который изменяет только li найденных элементов.

listItems = $("#productList li").each(function(){

        var product = $(this);
        var productid = product.children(".productId").val();
        var productPrice = product.find(".productPrice").val();
        var productMSRP = product.find(".productMSRP").val();

        totalItemsHidden.val(parseInt(totalItemsHidden.val(), 10) + 1);
        subtotalHidden.val(parseFloat(subtotalHidden.val()) + parseFloat(productMSRP));
        savingsHidden.val(parseFloat(savingsHidden.val()) + parseFloat(productMSRP - productPrice));
        totalHidden.val(parseFloat(totalHidden.val()) + parseFloat(productPrice));

    });
2

Для более точного ответа вам нужно опубликовать часть своей разметки. Вы можете немного упростить свой jQuery, например:

$("#productList li").each(function() {
    var product = $(this);
    var productid = $(".productId", product).val();
    var productPrice = $(".productPrice", product).val();
    var productMSRP = $(".productMSRP", product).val();

    // the rest remains unchanged
}
2
  • 1
    Я бы не стал этого делать, $(".productId", $(this))потому что это менее эффективный способ product.find(".productId"). Кроме того, вы кешировали, $(this)но никогда не использовали его. 22 дек.
  • Ах, хорошие моменты. Я редко назначаю $(this)другую переменную, но сделал это, чтобы код OP оставался похожим. 22 дек.
0

Чтобы решить эту проблему без jQuery, .each()вам нужно исправить свой код следующим образом:

var listItems = $("#productList").find("li");
var ind, len, product;

for ( ind = 0, len = listItems.length; ind < len; ind++ ) {
    product = $(listItems[ind]);

    // ...
}

Ошибки в исходном коде:

  1. for ... inтакже будет перебирать все унаследованные свойства; т.е. вы также получите список всех функций, определенных jQuery.

  2. Переменная цикла li- это не элемент списка, а индекс элемента списка. В этом случае индекс является нормальным индексом массива (т.е. целым числом)

В основном вы сохраняете, чтобы использовать, .each()поскольку это более удобно, но особенно, когда вы зацикливаете большие массивы, код в этом ответе будет намного быстрее.

Для других альтернатив .each()вы можете проверить это сравнение производительности: http://jsperf.com/browser-diet-jquery-each-vs-for-loop

1
  • 1
    Почему бы просто не уменьшить количество подобных циклов for (и вообще не удалить переменную len): for (ind = 0; ind <listItems.length; ind ++) { 14 сен '17 в 8:20
-1

   <script src="https://cdnjs.cloudflare.com/ajax/libs/jquery/3.4.0/jquery.min.js"></script>
   <script>
      $(document).ready(function() {
      $("form").submit(function(e){
          e.preventDefault();
       var name = $("#name").val();
       var amount =$("#number").val();
       var gst=(amount)*(0.18);
           gst=Math.round(gst);

       var total=parseInt(amount)+parseInt(gst);
       $(".myTable tbody").append("<tr><td></td><td>"+name+"</td><td>"+amount+"</td><td>"+gst+"</td><td>"+total+"</td></tr>");
       $("#name").val('');
       $("#number").val('');

       $(".myTable").find("tbody").find("tr").each(function(i){
       $(this).closest('tr').find('td:first-child').text(i+1);

       });

       $("#formdata").on('submit', '.myTable', function () {

                   var sum = 0;

          $(".myTable tbody tr").each(function () {
                    var getvalue = $(this).val();
                    if ($.isNumeric(getvalue))
                     {
                        sum += parseFloat(getvalue);
                     }                  
                     });

                     $(".total").text(sum);
        });

    });
   });

   </script>

     <style>
           #formdata{
                      float:left;
                      width:400px;
                    }

     </style>
  </head>


  <body>  

       <form id="formdata">  

                           <span>Product Name</span>
                           <input type="text" id="name">
                            <br>

                           <span>Product Amount</span>
                           <input type="text" id="number">
                           <br>
                           <br>
                           <center><button type="submit" class="adddata">Add</button></center>
       </form>
       <br>
       <br>

      <table class="myTable" border="1px" width="300px">
      <thead><th>s.no</th><th>Name</th><th>Amount</th><th>Gst</th><th>NetTotal</th></thead>

      <tbody></tbody>

      <tfoot>
             <tr>
                 <td></td>
                 <td></td>
                 <td></td>
                 <td class="total"></td>
                 <td class="total"></td>
             </tr>

      </tfoot>
      </table>

   </body>