格子表单/GRID-FORM已在Github 开源,如能帮到您麻烦给个星🤝
GRID-FORM 系列文章
- 基于 VUE3 可视化低代码表单设计器
- 嵌套表单与自定义脚本交互
- 文档网站搭建(VitePress)与部署(Github Pages)
- 必填项检验 BUG 修复实录
#1 缘起
格子表单支持设置字段为必填项
,组件会在数据提交前自检,发现有必填字段留空,则抛出异常。
增加子(嵌套)表单功能后,上述校验出现 BUG 🐛,感谢热心网友的 ISSUE 提醒。
#1.1 原因分析
原校验流程:
- 表单初始化时,构建必填项集合
formRequired : Map<String, Object>
(以字段编号作为 KEY,元素包括:label/字段中文,msg/提示信息,regex/正则表达式) - 校验时,遍历 formRequired ,匹配格则
- 若有字段(1个或多个)检查未通过,抛出异常
代码如下:
const _checkRequire = formObj=>{
let fails = []
Object.keys(formRequired).forEach(key=>{
let { regex, msg, label } = formRequired[key]
if(!formObj[key]) fails.push(`${label}(${key})未填写`)
else{
if(!!regex && !RegExp(regex).test(formObj[key])) {
fails.push(msg||`${label}(${key})校验未通过`)
}
}
})
if(fails.length){
props.debug && track(`[表单检查]`, fails)
return emits("failed", fails)
}
}
子表单下,字段编号可能重复,嵌套对象下遍历时不能正常匹配。如上图表单的校验过程 :
// 构建的规则
const formRequired = {
school: { label:"学校名称", regex: "", msg:"" }
}
// 用户填写表单
const formData = {
name: "fdgs",
origin: "21,
age: 123,
educates: [
{ type:"小学", from:"2024-02-18", school:"e121321" }
]
}
// 检验时,遍历 formRequired,提取出 school,发现在 formData 中没有 formData['school'],于是报错
#2 思路
首先想到的解决方案,就是支持嵌套对象的检查:递归对当前层级的数据对象进行检查,直至没有下层嵌套。
/**
* 检测必填项
* 子表单(非 SIMPLE)必填无法正常检测
* https://github.com/0604hx/grid-form/issues/3
*
* @param {Array<import('.').FormItem>} items - 表单定义项
* @param {Object} bean - 与 items 对应的数据对象
* @param {Array<String>} fails - 错误清单
* @param {String} prefix - 前缀文本
*/
const _checkRequire = (items, bean, fails, prefix="")=>{
for(const item of items){
if(item._container === true){
switch(item.category){
case SINGLE:
_checkRequire(item.items, bean[item._uuid]||{}, fails)
break
case MULTIPLE:
const rows = bean[item._uuid]
if(Array.isArray(rows)){
for (let i = 0; i < rows.length; i++) {
const row = rows[i]
_checkRequire(item.items, row, fails, `[${item._text||item.title}的第${i+1}条]`)
}
}
break
default:
_checkRequire(item.items, bean, fails)
}
}
else if(item._required == true){
//检查必填表单项是否符合预期
if(!bean[item._uuid])
fails.push(`${prefix}${item._text}(${item._uuid})未填写`)
else{
if(!!item._regex && !RegExp(item._regex).text(bean[item._uuid]))
fails.push(prefix+(item._message || `${item._text}(${item._uuid})校验未通过:${item._regex}`))
}
}
}
}
新思路删除了中间变量 formRequired
,仅在提交前遍历全部表单项进行校验,能够精准到子表单的某一行,理论上支持无限嵌套😎。
#3 尾声
修复后,效果如下: