表单清空后,旧数据为什么又回来了?
编辑已有资料时,删掉最后一行电话号码,保存成功,再打开,号码却又回来了。输入框看着是空的,服务端收到的请求和页面保存后的状态,未必也空了。
这个问题出现在一套配置式表单中。界面字段需要转换成接口数据,详情返回后再反向转换。一个表格控件对应请求里的一个数组,删除行的意图可能在任意一段转换中丢失。
为什么跳过空值,会把旧值留下?
更新逻辑先复制原详情,再用表单值覆盖。这个办法能保留用户没有编辑的字段,但如果转换时遇到空字符串就跳过,旧值也会被保留。
例如原详情是 displayName: '旧名称',用户清空以后,表单值变成 ''。转换器不覆盖这个字段,请求就仍带着“旧名称”。对 false、0 使用同样的真假判断,还会误删正常值。
可选的处理方式有逐字段生成更新请求,或在旧详情上覆盖明确提交的字段。无论选哪种,都要先定义值的含义:
| 输入 | 应当区分的意图 |
|---|---|
| 没有这个 key | 没编辑,或控件没有挂载 |
'' | 清空文本 |
null | 明确置空可空字段 |
[] | 删除所有表格行 |
false、0 | 正常值 |
undefined | 结合字段是否隐藏、是否挂载判断;JSON 不保留它 |
| 非法日期或错误类型 | 校验失败,不能当作清空 |
项目保留了更新时合并原详情的方式,但先检查 key 是否存在,再按字段规则处理值。可见字段的空字符串可以覆盖旧值,允许置空的情况转换成 JSON 能提交的 null;隐藏控件未挂载产生的 undefined,则不能顺手清掉服务端数据。创建没有旧详情,部分空值仍可以省略。
用户删光了行,为什么提交值里没有空数组?
表单库的变更事件能报告 { phonesField: [] },完整表单快照却可能过滤空数组,连 key 都不留下。提交转换器只看快照,就会把“全部删除”理解成“没有修改”。
一种办法是调整表单库的取值规则;另一种是单独保留明确的删除意图。项目采用后者,记录当前可见、可编辑、允许整体清空的表格字段,生成提交快照时补回 []。
这个记录属于本次编辑。重新加入行后要撤销,切换记录、重置详情或换表单时也要清掉。测试时,变更事件应带 [],完整快照应故意缺 key,才能复现两份值不一致的情况。
请求已经清空,页面为什么还显示旧行?
还要看反向回填。服务端返回 phones: [],详情转换器却只处理非空数组,最后得到 {}。表单的赋值方法如果采用合并更新,缺少这个字段就会继续保留旧行。
项目因此在详情转换和通用行映射中都保留空数组:响应明确为空,就产生对应的空表格值,覆盖旧行;响应没有这个字段,则不由它修改当前值。只有非法脏行的响应也要单独处理,不能伪装成用户清空。
这样,同样的空数组在提交和回填两侧都有明确含义。
删除中间行时,未展示的属性怎么保留?
表格通常只展示原始记录的一部分。合并更新时若按行下标找旧数据,删除中间一行后,后面的隐藏属性就会配错行。
项目为加载进来的每行附带来源标识,优先使用原记录 ID,没有 ID 时使用本次加载的位置。编辑后凭这个标识找回原始行,再按写请求白名单保留允许提交的属性,最后去掉内部标识和只读字段。
位置标识只适用于本次加载基线,跨刷新或服务端重排需要稳定的行 ID 或版本信息。