为啥在单击“全选”按钮后,复选框会被选中,然后又被取消选中?

Posted

技术标签:

【中文标题】为啥在单击“全选”按钮后,复选框会被选中,然后又被取消选中?【英文标题】:Why do boxes become checked and then unchecked after clicking a “Check All” button?为什么在单击“全选”按钮后,复选框会被选中,然后又被取消选中? 【发布时间】:2021-08-16 05:55:19 【问题描述】:

我在这里尝试修复一个 JS 函数。单击“检查全部”按钮时会触发此功能。单击此按钮时,应选中并禁用表中的所有项目。当我运行此功能并单击 Check All 按钮时,所有项目都被短暂选中,然后它们又回到未选中状态。我做错了什么?

PS:我尝试添加 e.preventDefault() 和末尾 功能和它不起作用

$(document).ready(function () 
        $('body').on('change', '#checkAll', function (e) 
            if(this.checked)
                let boxes = $("input.promo-action-checkbox");
                boxes.toArray().forEach(element => 
                    console.log(element);
                    $(element).attr('disabled', 'disabled');
                    var name = $(element).data('name');
                    var number = $(element).data('number');
                    var user = $(element).data('user');
                    $.ajax(
                        method: 'post',
                        url: '/checker',
                        contentType: "application/json",
                        data: JSON.stringify(
                            name: name,
                            number: number,
                            user: user
                        ),
                        dataType: 'json',
                        error: function () 
                            $(element).attr('disabled', '');
                        
                        )
                    
                );

html表格中的列是如何组成的:

 var table = $('#datatable').DataTable(
    pageLength: 20,
    lengthChange: false,
    language: 
      paginate: 
        previous: '<i class=\'fas fa-angle-left\'>',
        next: '<i class=\'fas fa-angle-right\'>'
      
    ,
    ordering: true,
    processing: true,
    serverSide: true,
    ajax: 
      url: '/table/',
      dataSrc: 'results'
    ,
    columns: [
      
        data: null,
        render: function (data, type, row, meta) 
          let rowHtml = '<div class="custom-control custom-checkbox mb-3"> <input class="custom-control-input promo-action-checkbox" id="checkbox-' + meta.row + '"  data-name="' + row.name + '" data-phone="' + row.number + '" data-admin="' + row.user + '" type="checkbox"'
          if (row.fulfilled) 
            rowHtml += ' disabled checked'
          
          rowHtml += '> <label class="custom-control-label"  for="checkbox-' + meta.row + '"></label></div>'
          return rowHtml
        
      ,
      
        searchable: true,
        data: 'name'
      
    ]
  );

这是可行的,但是“checkAll”框没有被勾选。此表也不在表单内。

$('#checkAll').click(function (e) 
 e.preventDefault()
    $('input.action-checkbox').prop('checked', this.checked);  
    $('input.action-checkbox').prop('disabled', true);
    return false;
)

表结构:

        <div class="table-responsive">
            <table class="table align-items-center table-flush table-striped" id="datatable-promo-code">
                <thead class="thead-light">
                <tr>
                    <th>Check All <input id = "checkAll"  type= "checkbox"></th>
                    <th>Name</th>
                    <th>Info</th>
                    <th>address</th>
                    <th>Email</th>
                    <th>Number</th>
                </tr>
                </thead>
                <tbody>
                <tr>
                    <td></td>
                    <td></td>
                    <td></td>
                    <td></td>
                    <td></td>
                    <td></td>
                </tr>
                </tbody>
            </table>
        </div>

【问题讨论】:

请添加所有相关代码(HTML、CSS 和 javascript),以便我们复制您的问题。 @ScottMarcus 我刚刚更新了它 您的 ajax 调用一定失败了,因为 error 函数是重新启用它们的原因。您正在传递datatype: 'json',因此无需调用stringify,jQuery 会为您执行此操作,只需直接传递 json 对象即可。至于他们为什么不勾选,不知道,没有相关的代码。 现在,我不介意他们被禁用。我只希望 ClickAll 按钮检查并禁用所有其他按钮并保持这种状态,直到我手动刷新页面 检查你的 if(this.checked) 语句被调用了多少次。我之所以这么说,是因为在将事件处理程序多次绑定到同一个对象之前,我在使用 JQuery On 方法时遇到了问题。 【参考方案1】:

很难说,因为我实际上无法运行您的代码...但我会将 console.log 放入渲染函数中,只是为了查看它何时被调用。我的猜测是,在您的 'change' 侦听器完成所有请求之前,您的表正在重新渲染。如果是这种情况,您需要等待所有承诺结束,然后再手动刷新页面或重新呈现表格......类似......

$(document).ready(function () 
  $('body').on('change', '#checkAll', async function (e) 
    if(this.checked) 
      let boxes = $("input.promo-action-checkbox");
      const promises = boxes.toArray().map(element => 
        return new Promise(function (resolve, reject) 
          $(element).attr('disabled', 'disabled');
          var name = $(element).data('name');
          var number = $(element).data('number');
          var user = $(element).data('user');
          $.ajax(
              method: 'post',
              url: '/checker',
              contentType: "application/json",
              data: JSON.stringify(
                  name: name,
                  number: number,
                  user: user
              ),
              dataType: 'json',
              error: function () 
                  $(element).attr('disabled', '');
                  reject();
              ,
              success: function() 
                resolve()
              
          );
        );
      );

      await Promise.all(promises);
      // refresh the page
      document.location.reload()
      // or re-render your table... no ideia how to that though...
      someMagicFunctionToReRenderYourTable()
    
  );
);

【讨论】:

谢谢你!我得到一个 ReferenceError: promises is not defined。顺便说一下,我正在 中实现这个 你能把代码给我看看吗?您可能会收到此错误,但为此您可能已将 Promise.all 放在 if 之外... 请检查我对这个问题的更新,我已经发布了有效的方法,但我遇到了显示已勾选复选框的问题。我还包括了表格的样子【参考方案2】:

目前尚不清楚为什么所有复选框不仅需要被选中而且还需要禁用。单击 "button" 后,其余代码在做什么也不是很清楚。更重要的是,这是&lt;table&gt;&lt;form&gt; 中吗?如果是这样,那么&lt;form&gt; 可能会自行重置(“提交”事件的默认行为)

抛开所有这些,我们可以将代码隔离成更小的部分。这样我们就可以在不破坏其他内容(即 AJAX POST 请求)的情况下修复某些内容(即像 &lt;input&gt; 这样的交互式元素)。

下面的例子将:

    监听“change”事件以触发#checkAll 一旦触发,事件处理程序lockCells() 将运行。
    $('#checkAll').on('change', lockCells);
    
    lockCells(event) ... 传递 Event Object... ...检查#checkAll (this) 是否为.checked
    let status = this.checked ? true : false;
    
    ...然后收集任何&lt;table&gt; 中的所有&lt;input&gt; 并在每个.prop() 上运行方法。
     $('table input').prop(...)
    
    ...带有“已禁用”和“已检查”的参数,在第 4 步之前确定的真/假布尔值
    
      'disabled': status,
      'checked': status
    
    

重要的是要注意:虽然方法.attr() 用于操作属性,但.prop() 是属性的更好选择,尤其是具有布尔值(T/F)的属性。详情请参考question。

$('#checkAll').on('change', lockCells);

function lockCells(event) 
  let status = this.checked ? true : false;
  $('table input').prop(
    'disabled': status,
    'checked': status
  );
;
label 
  display: inline-block;
  padding: 3px 5px;
  border: 1px inset grey;
  border-radius: 6px;
  margin: 5px 10px;
  float: right;
  cursor: pointer;


label::before 
  content: 'Disable ';


#checkAll:checked+label::before 
  content: 'Enable ';


table input 
  display: block;
  width: 10ch;
<input id='checkAll' type='checkbox' hidden>
<label for='checkAll'> All Cells</label>
<table>
  <tbody>
    <tr>
      <td><input type='checkbox'></td>
      <td><input type='checkbox'></td>
      <td><input type='checkbox'></td>
      <td><input type='checkbox'></td>
    </tr>

    <tr>
      <td><input type='checkbox'></td>
      <td><input type='checkbox'></td>
      <td><input type='checkbox'></td>
      <td><input type='checkbox'></td>
    </tr>

    <tr>
      <td><input type='checkbox'></td>
      <td><input type='checkbox'></td>
      <td><input type='checkbox'></td>
      <td><input type='checkbox'></td>
    </tr>

    <tr>
      <td><input type='checkbox'></td>
      <td><input type='checkbox'></td>
      <td><input type='checkbox'></td>
      <td><input type='checkbox'></td>
    </tr>

  </tbody>
</table>

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

【讨论】:

请检查我对这个问题的更新,我已经发布了有效的方法,但是原始复选框没有显示它已被选中,所以我几乎在那里。顺便说一下,我还包括了表格的外观。 您需要跟踪两种状态。您可以通过使用复选框以实用的方式或更简单的方式执行此操作。发布的新代码与我的回答非常相似。不同之处在于您的状态从一种状态开始并保持这种状态,而我的状态从一种状态切换到另一种状态(切换)。顺便说一句,将“已检查”值从 this.checked 更改为 true。在当前上下文中,这指向#checkAll 我对您的回答的问题是,在消失之前检查了盒装半秒,使用 e.preventDefault() 和返回 false,更改仍然存在,但我不知道为什么。此外,当我单击复选框时,该框不会被明显选中。也许这与我使用 .click(function (e)) 而不是 onchange 有关? 在您的布局中,复选框由 dataTable 插件动态生成,我假设每个输入都有 3 个 data-* 属性,这些属性的值由 AJAX 获得的 JSON 填充。看起来所有这些都是通过单击#checkall 来实现的。复选框最初是在页面加载时生成的吗?您需要为服务器中的复选框分配值吗? #checkAll 是隐藏的,与之相关的标签看起来像一个按钮。如果您希望看到它被选中,只需删除 hidden 属性。不要使用 e.preventDefault()。更改事件是专门用于输入的事件,其他表单控件不使用点击事件。使用我发布的内容,仅将选择器“表格输入”更改为“input.action-checkbox”。

以上是关于为啥在单击“全选”按钮后,复选框会被选中,然后又被取消选中?的主要内容,如果未能解决你的问题,请参考以下文章

流水账

jQuery实现全选效果

jQuery实现全选效果

单击模态对话框按钮后如何取消选中该复选框?

JQuery对checkbox的操作

vue checkbox多选框按钮添加全选按钮