基于单选框选择的Ajax请求后复选框选中状态异常问题
问题解决:单选按钮快速切换导致复选框状态异常
问题场景
我有一组复选框,其选中/未选中状态由3个单选按钮控制。单选按钮切换时会发起Ajax请求,根据单选按钮的值确定哪些复选框需要选中。但快速切换两个单选按钮时,最终选中的复选框会同时包含两个单选按钮对应的选项:
- 选中“manager”时,复选框仅显示manager对应的选项;
- 选中“test”时,复选框仅显示test对应的选项;
- 快速选中“manager”再选“test”后,复选框同时包含manager和test的选项,但最后选中的是“test”,应该只保留test对应的复选框状态。
原代码
$(document).on("change", "input[type=radio][name=\"user[profile]\"]", function (){ let value = $( this ).val(); let data = {profile_id: value} let url = HOME_URL + '/API/getmodules/' + value $('input:checkbox[id^=\"user_access_\"]').prop('checked', false) //initialize all checkboxes at uncheck $('span[class^=\"badge badge-success\"]:not([id^=\"span-example\"])').contents().unwrap(); $.post(url, data).then(function (response) { let modulesData = response.modules for (let module in modulesData){ let moduleValue = modulesData[module].id let $modules = $('input:checkbox[id^=\"user_access_\"][value=' + moduleValue + ']') let $modulesLabel = $('label[for=\"user_access_' + modulesData[module].toolId + '_' + moduleValue + '\"]') $modules.prop('checked', true) // check the checkboxes depends on the data response $modulesLabel.empty(); $modulesLabel.append('<span class="badge badge-success">' + modulesData[module].name + '</span>'); } }) })
问题原因
这是典型的Ajax竞态条件问题:快速切换单选按钮时,前一次的Ajax请求还未完成,后一次请求已触发并执行了复选框清空操作,但前一次请求的响应后续返回后,会再次勾选其对应的选项,最终导致两次请求对应的复选框选项都被选中。
解决方案
维护一个Ajax请求的引用,每次触发新的请求前,终止上一次未完成的请求,确保只有最后一次请求的响应会处理复选框状态。
修改后的代码
// 维护全局请求引用,用于终止未完成的请求 let pendingRequest = null; $(document).on("change", "input[type=radio][name=\"user[profile]\"]", function (){ let value = $(this).val(); let data = {profile_id: value}; let url = HOME_URL + '/API/getmodules/' + value; // 如果有未完成的请求,先终止它 if (pendingRequest) { pendingRequest.abort(); pendingRequest = null; } // 清空所有复选框状态和标签样式 $('input:checkbox[id^=\"user_access_\"]').prop('checked', false); $('span[class^=\"badge badge-success\"]:not([id^=\"span-example\"])').contents().unwrap(); // 发起新请求并保存引用 pendingRequest = $.post(url, data).then(function (response) { let modulesData = response.modules; for (let module in modulesData){ let moduleValue = modulesData[module].id; let $modules = $('input:checkbox[id^=\"user_access_\"][value=' + moduleValue + ']'); let $modulesLabel = $('label[for=\"user_access_' + modulesData[module].toolId + '_' + moduleValue + '\"]'); $modules.prop('checked', true); $modulesLabel.empty(); $modulesLabel.append('<span class="badge badge-success">' + modulesData[module].name + '</span>'); } }).always(function() { // 请求完成(成功/失败)后清空引用 pendingRequest = null; }); });
关键修改说明
- 新增
pendingRequest变量存储当前未完成的Ajax请求引用; - 每次触发单选按钮变更时,先检查并终止未完成的请求,避免旧请求的响应干扰新状态;
- 使用
always方法确保无论请求成功或失败,都清空请求引用,避免影响后续操作。
内容的提问来源于stack exchange,提问作者Lino
相关产品推荐
相关产品推荐

