Javascript控件无法识别编辑状态问题求助
表单控件编辑状态判断失效问题解决
我有一个简易表单控件,规则为:若用户已编辑字段,则不从数据库更新该字段并标记;若未编辑,则从数据库获取最新值更新控件。目前该逻辑失效,约半数情况用户编辑后控件仍被数据库值覆盖。
相关代码
生成控件的代码
控件通过ViewModel的foreach动态生成:
@foreach (var row in Model.controls) { <input type="text" name="@row.Name" id="@row.NameID" value="@row.Value" edited="0" class="form-control data-field" onfocus="return ControlEdited(this.id)" style="width: 300px" /> }
控件焦点触发的标记函数
function ControlEdited(id) { document.getElementById(id).setAttribute('edited', 1); document.getElementById(id).style.backgroundColor = "yellow"; }
核心问题函数UpdateControls
该函数本应仅更新未编辑字段,但时常失效覆盖已编辑内容:
function UpdateControls() { $(".data-field").each(function () { var nameAttr = $(this).attr('name'); var id = $(this).attr('id'); var edited = $(this).attr('edited'); var stationID = document.getElementById('stationDD').value; if (edited == 0) { var url = "/Manager/UpdateControlsFromDB/"; $.ajax({ url: url, data: { name: nameAttr, station: stationID }, cache: false, type: "POST", success: function (data) { if (data != null) { document.getElementById(id).value = data; } }, error: function (response) { alert("Issue updating the page controls from database. Information: " + response.responseText); } }); } else { // 用户已编辑,不更新 } }); }
问题根源分析
- AJAX异步竞态问题:判断
edited状态是在发起AJAX请求前完成的,但请求是异步的。如果用户在请求发起后、响应返回前点击控件将edited设为1,回调依然会执行更新,因为状态判断没有在回调阶段重新校验。 onfocus标记不准确:onfocus仅标记用户获得焦点,但用户可能获取焦点后未编辑就离开,此时不该阻止更新;反之,若用户在焦点触发后编辑,异步请求的响应可能仍会覆盖内容。- 自定义属性类型隐患:
edited是DOM字符串属性,使用==弱等于判断可能出现类型匹配问题(比如字符串"0"和数字0比较没问题,但如果属性值异常会导致判断失效)。
解决方案
1. 回调阶段重新校验状态
在AJAX成功回调中再次检查控件的edited状态,确保更新时控件确实未被编辑:
function UpdateControls() { $(".data-field").each(function () { var $control = $(this); var nameAttr = $control.attr('name'); var id = $control.attr('id'); var stationID = $('#stationDD').val(); var url = "/Manager/UpdateControlsFromDB/"; $.ajax({ url: url, data: { name: nameAttr, station: stationID }, cache: false, type: "POST", success: function (data) { if (data != null) { var $target = $('#' + id); // 回调时重新校验状态,用字符串严格匹配避免类型问题 if ($target.attr('edited') === "0") { $target.val(data); } } }, error: function (response) { alert("Issue updating the page controls from database. Information: " + response.responseText); } }); }); }
2. 改用oninput标记真实编辑行为
把onfocus换成oninput,只有用户真正输入内容时才标记为已编辑,避免误标记:
@foreach (var row in Model.controls) { <input type="text" name="@row.Name" id="@row.NameID" value="@row.Value" edited="0" class="form-control data-field" oninput="ControlEdited(this.id)" style="width: 300px" /> }
3. 使用jQuery data()存储状态(更可靠)
放弃自定义DOM属性,用data()存储编辑状态,避免字符串类型问题:
// 页面加载时初始化状态 $(function() { $(".data-field").data('edited', 0); }); function ControlEdited(id) { $('#' + id).data('edited', 1).css('backgroundColor', 'yellow'); } function UpdateControls() { $(".data-field").each(function () { var $control = $(this); var nameAttr = $control.attr('name'); var id = $control.attr('id'); var stationID = $('#stationDD').val(); $.ajax({ url: "/Manager/UpdateControlsFromDB/", data: { name: nameAttr, station: stationID }, cache: false, type: "POST", success: function (data) { if (data != null) { var $target = $('#' + id); if ($target.data('edited') === 0) { $target.val(data); } } }, error: function (response) { alert("Issue updating the page controls from database. Information: " + response.responseText); } }); }); }
4. 可选:添加AJAX请求取消机制
如果UpdateControls会被频繁调用,可取消未完成的旧请求,避免旧响应覆盖新状态:
var controlRequests = {}; function UpdateControls() { $(".data-field").each(function () { var $control = $(this); var id = $control.attr('id'); var nameAttr = $control.attr('name'); var stationID = $('#stationDD').val(); // 取消当前控件未完成的旧请求 if (controlRequests[id]) { controlRequests[id].abort(); } controlRequests[id] = $.ajax({ url: "/Manager/UpdateControlsFromDB/", data: { name: nameAttr, station: stationID }, cache: false, type: "POST", success: function (data) { delete controlRequests[id]; if (data != null) { var $target = $('#' + id); if ($target.data('edited') === 0) { $target.val(data); } } }, error: function (response) { delete controlRequests[id]; alert("Issue updating the page controls from database. Information: " + response.responseText); } }); }); }
内容的提问来源于stack exchange,提问作者Eli
相关产品推荐
相关产品推荐

