【问题标题】:Accessing and comparing data in jQuery loop在 jQuery 循环中访问和比较数据
【发布时间】:2023-02-21 01:09:06
【问题描述】:

我的页面上有一个动态构建的表格,其中包含可编辑的数据字​​段。该表看起来像这样:

<tr>
    <td class="identifier">1</td>
    <td class="c1"><input type="number" data-id="123" value="123" /></td>
    <td class="c2"><input type="number" data-id="456" value="456" /></td>
</tr>
<tr>
    <td class="identifier">2</td>
    <td class="c1"><input type="number" data-id="321" value="321" /></td>
    <td class="c2"><input type="number" data-id="654" value="654" /></td>
</tr>

我在所有 tr 元素上使用 jQuery .each() 循环,并尝试将每个输入的值与 data=id 进行比较(data-id 在服务器上设置为等于框的初始值)所以我可以在用户单击按钮时保存更改的值。

我的函数看起来像这样:

$('tr').each(function (index, element) {
    var idToSave = $(element).children('.identifier').first().text();
    var toSave = false;
    var $cone = $(element).children('td.pup input[type=number]').first();
    var $ctwo = $(element).children('td.van input[type=number]').first();

    var x = $cone.text();
    alert('Text: ' + x);
    var y = $cone.val();
    alert('Val: ' + y);
    var z = $cone.data("id");
    alert('Data: ' + z);
    
    if ($cone.text() != $cone.data("id")) {
        toSave = true;
    }

    if (toSave) {
        //Do an ajax call to the save method, passing in values
    }
});

当我运行我的 jQuery each() 函数时,我正确地看到了标识符(通过我已经删除的警报验证)但是变量 x、y 和 z 都返回为未定义。我已经确认变量名称在我的页面中是唯一的(它们在我的实际页面中不是 x、y、z,只是这个简化版本)并且我已经尝试了许多版本的代码,包括使用 .attr("data- id") 和 .dataset.id 从我的输入中提取数据。我觉得我缺少一些简单而明显的东西。

任何人都可以提供任何建议吗?

【问题讨论】:

    标签: html jquery


    【解决方案1】:

    这里的主要问题似乎是:

    • .children() 仅沿着 DOM 树向下移动一个级别 (docs)
      这是导致 undefined 值的原因,因为从 tr 开始,您只能搜索直接子代(即一些 td),而不是 td 子代 input
    • 第一次使用.data('id')返回类型号
      (因为它解析为来自data-id="123" 的数字)
    • td 中缺少.pup.van 类(缺少td.puptd.van 选择器;此类没有td,因此找不到输入)

    解决方案

    • 使用.find(selector)更新您的.children(selector)方法以查找深层嵌套元素
    • '' 连接到您的 .data('id') 以使其成为一个字符串并检查您的输入值。
    • 通过检查您需要的所有条件来更新您的 toBeSaved 值

    在下面的示例中,我使用了input.keyup() 的侦听器来在每次输入更改时运行.each() 函数

    // I'm setting up a keyup listener to run our .each() every time some input get a keyup event
    $('input').keyup(function() {
      console.clear()
      // I'm using 'tbody tr' as selector to exlude the first 'tr' (the header tr aka 'thead tr') 
      $('tbody tr').each(function(index, element) {
    
        // Use .find() to search for children element
    
        // this is because .children() method differs from .find() 
        // in that .children() only travels a single level down the DOM tree 
        var idToSave = $(element).find('.identifier').first().text();
        var c1 = $(element).find('td.c1 input[type=number]').first();
        var c2 = $(element).find('td.c2 input[type=number]').first();
    
        // Check if some value needs to be saved (using .attr() to get 'data-id' value)
        var toSave = c1.val() !== c1.data("id") + '' || c2.val() !== c2.data('id') + '';
    
        if (toSave) {
          // Optionally build queryString params for your fetch
          /// Note that to do this, i added 'name' attribute in our input
          const rowSerialized = $(element).find('input').filter(function(el) {
    
            // Including only fields with updated value
    
            const res = ($(this).data('id') + '') !== $(this).val();
            // Note that .data() will return number the first time
    
            return res;
          }).serialize();
    
          // Optionally build a diff object from the serialized string
          const rowDiffsObject = parseSerializedRow(rowSerialized)
    
          console.log("Saving Row With Id: ", idToSave, "
    Diff Object: ", rowDiffsObject);
    
          // Just for this example i'm faking save by updating the data-id
          c1.data('id', c1.val());
          c2.data('id', c2.val());
        }
      });
    })
    
    // just convert from serialized string
    // to diffs object
    function parseSerializedRow(rowSerialized) {
      let rowDiffs = {}
      rowSerialized.split('&').forEach((field) => {
        const split = field.split('=');
        const fieldName = split[0];
        const fieldValue = split[1];
        rowDiffs[fieldName] = fieldValue;
      });
      return rowDiffs;
    }
    <script src="https://cdnjs.cloudflare.com/ajax/libs/jquery/3.3.1/jquery.min.js"></script>
    <table>
      <thead>
        <tr>
          <th>Id</th>
          <th>Data 1</th>
          <th>Data 2</th>
        </tr>
      </thead>
      <tbody>
        <tr>
          <td class="identifier">1</td>
          <td class="c1"><input type="number" name="data1" data-id="123" value="123" /></td>
          <td class="c2"><input type="number" name="data2" data-id="456" value="456" /></td>
        </tr>
        <tr>
          <td class="identifier">2</td>
          <td class="c1"><input type="number" name="data1" data-id="321" value="321" /></td>
          <td class="c2"><input type="number" name="data2" data-id="654" value="654" /></td>
        </tr>
      </tbody>
    </table>
    <p>Update the values to see when some row needs to update</p>

    这样,每次更新其中一行时,您都可以执行保存。

    请注意,使用 .data() 获取初始值 (data-id="123") 将返回一个数字而不是字符串。这是因为我每次检查 .data('id') 时都会连接 +''

    【讨论】:

    • 哦。事实上,这就是问题的症结所在——children() 只向下看一个级别。 'pup' 和 'van' 类是一个疏忽,我忘记从我的实际代码中切换真实的东西以匹配简化的。在我的辩护中,我已经花了 4 个多小时来解决这个问题,而且当时是半夜。
    • 我再次使用 .data() 而不是 .attr() 更新了帖子(结果相同)。请注意,它将返回一个数字,因为 data-id="123" 的解析变成了 123 而不是 '123',这就是为什么我在与 .val() 比较之前连接 ''。附言半夜有利也有弊 :) 我说的是夜间的忠实粉丝
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2017-06-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多