多次切换点击调用相同 AJAX,不一致的数据库更新

Multiple toggle clicks calls same AJAX, inconsistent database updates

我的页面上有几个开关,全部使用 class psettings,它允许触发单个脚本执行 AJAX 调用以更新 MySQL 数据库中的标志 table。如果我慢慢点击,这很好用。我可以以正常速度单击所有按钮,并且数据库按预期更新但未选中,有时不会清除数据库中的标志。如果我走慢,在点击之间暂停,它工作正常。我无法阻止用户点击开关的速度有多快,但需要一种方法来确保更新一致,可能是延迟或刷新等。

        <script type="text/javascript">
        $('.psettings').change(function(){
          //event.preventDefault();

          var token  = $("input[name=<?php echo csrf_token(); ?>").val();
          var ename  = this.name;
          var evalue = ' ';
          if($("input[type='checkbox']").is(":checked"))
          {
            var evalue = 'X';
          }
          
          $.ajax({
            type: 'post',
            headers: {'X-Requested-With': 'XMLHttpRequest'},
            url:  '<?php echo base_url('setprivacy');?>',
            data: {'<?php echo csrf_token(); ?>' : token, 'element_name' : ename, 'checked' : evalue },
            dataType: 'json',
            success:function(data){
              $('input[name="fmpfy_tk"]').val(data.csrf);
            },
            error:function(data)
            {
              $('input[name="fmpfy_tk"]').val(data.csrf);
              alert('Error occurred ' + data.col_name);
            }
          });

          
        });
    </script>
            <?php
            echo form_open();
            ?>
            <div class="row mt-3 pb-2">
                <div class="col">
                    <h2 class="title-text grayer pb-1"><i class="fa-solid fa-eye-slash pe-2"></i>Privacy Settings</h2>
                    <div class="row mt-3 py-2 base-text">
                        <div class="col">
                            <div class="form-check form-switch">
                              <input class="form-check-input psettings" type="checkbox" role="switch" name="flag_display_fullname" value="">
                              <label class="form-check-label" for="flag_display_fullname">Display full name in profile and posts</label>
                              <i class="fa-solid fa-circle-info ps-3 off-black" rel="tooltip" title="<?php echo lang('Tooltips.display_fullname'); ?>"></i>
                            </div>
                            <div class="form-check form-switch">
                                <input class="form-check-input psettings" type="checkbox" role="switch" name="flag_display_smaccounts" value="">
                                <label class="form-check-label" for="flag_display_smaccounts">Display social media accounts on posts</label>
                                  <i class="fa-solid fa-circle-info ps-3 off-black" rel="tooltip" title="<?php echo lang('Tooltips.display_sm_accounts'); ?>"></i>
                            </div>
                            <div class="form-check form-switch">
                                <input class="form-check-input psettings" type="checkbox" role="switch" name="flag_receive_fy_emails" value="">
                                <label class="form-check-label" for="flag_receive_fy_emails">Receive periodic emails from FY.</label>
                                  <i class="fa-solid fa-circle-info ps-3 off-black" rel="tooltip" title="<?php echo lang('Tooltips.receive_fy_emails'); ?>"></i>
                            </div>
                        </div>
                    </div>
                </div>
            </div>
            <?php
            echo form_close();
            ?>

    public function maintain_privacy_settings()
{
    helper(['form','url']);

    if ($this->request->isAJAX())
    {   
        $UserModel = new \App\Models\User_model();

        //Determine update column name
        $element_name = $this->request->getPost('element_name');
        $col_name;

        switch ($element_name)
        {
          case 'flag_display_fullname':
            $col_name = 'show_fullname';
            break;
          case 'flag_display_smaccounts':
            $col_name = 'display_sm_accounts';
            break;
          case 'flag_receive_fy_emails':
            $col_name = 'fy_notification_emails';
            break;
        }

        if($UserModel->set_privacy_flag($this->data['userid'],$col_name,$this->request->getPost('checked')))
        {
            return json_encode(['success'=> 'success', 'csrf' => csrf_hash()]);
        }
        else
        {
            return json_encode(['error' => 'error', 'csrf' => csrf_hash(), 'col_name' => $this->request->getPost('element_name') ]);
        }
    }
}

当多个请求将被发送到服务器但它们的响应不会按顺序返回时,就会出现您的问题。所以服务器上存储的内容将与 UI.

上的存储内容不同

要解决此问题,您可以使用多种技术,但最简单的方法是阻止特定的 UI 元素,直到从服务器收到响应。为此,您可以在 ajax 调用之前禁用元素,然后在函数成功或失败时启用它。

您还可以为每个请求分配一个序列号,并应用最高的序列号并忽略其余的。

您还可以为您的请求实现一个队列并按顺序处理它们。

编辑:

您的 jquery 代码也有问题。您没有得到特定输入的检查状态。试试下面的方法:

if($(`input[name='${ename}']`).is(":checked"))
{
    var evalue = 'X';
}