常见错误与排查
本文汇总 Piying-View 运行时的真实报错信息(含 emoji 前缀)与高频「不报错但不符合预期」的现象,帮助你快速定位问题。
| 报错信息 | 出处 | 直接原因 |
|---|---|---|
🈳define:[xxx]❗ |
组件渲染 | types 里没有该 key,组件类型仍是字符串没被解析成组件 |
🈳wrapper:[xxx]❗ |
Wrapper 查找 | actions.wrappers 引用了未在 fieldGlobalConfig.wrappers 注册的包装器 |
🏷️ fieldControl❗ |
[formControl] 指令 |
把 Group / Array 等非叶子控件绑到了 [formControl] |
📍 fieldControlBind:[...]->[...]❗ |
[formControl] 指令 |
目标字段根本没有控件(非表单控件 / nonFieldControl) |
移动视图项失败 |
layout |
layout({ keyPath }) 的目标路径查询不到任何父级 |
change wrapper not found |
wrappers.changeAsync |
定位函数返回了空,没找到要修改的 wrapper |
child index not found |
路径计算 | 控件与其父级 children 的对应关系被破坏 |
action:[xxx]❗ |
JSON Schema 转换 | JSON 里写了自定义 action,但没在 customActions 中注册 |
未知类型:xxx |
JSON Schema 转换 | JSON Schema 的 type 无法识别 |
options multi conflict |
JSON Schema 转换 | 单选/多选配置互相冲突 |
patternProperties->xxx: 定义未找到 |
JSON Schema 转换 | patternProperties 引用了不存在的定义 |
依赖->xxx: 定义未找到 |
JSON Schema 转换 | 关键字依赖的字段定义缺失 |
一、渲染类问题
Section titled “一、渲染类问题”1. 🈳define:[xxx]❗
Section titled “1. 🈳define:[xxx]❗”含义:库拿到了一个字符串类型的组件定义,但没能把它换成真实组件。
排查顺序:
options.fieldGlobalConfig.types是否传了?- key 拼写是否和
setComponent('my-input')完全一致(区分大小写)? types的值是否写成了裸组件类?必须是{ type: 组件 }对象:
2. 🈳wrapper:[xxx]❗
Section titled “2. 🈳wrapper:[xxx]❗”含义:actions.wrappers 引用了未注册的包装器名。
解决:在 fieldGlobalConfig.wrappers 中注册同名包装器。
3. change wrapper not found
Section titled “3. change wrapper not found”出现在 actions.wrappers.changeAsync(indexFn, actions):indexFn 返回了空值。
二、绑定类问题(手动模式)
Section titled “二、绑定类问题(手动模式)”4. 🏷️ fieldControl❗
Section titled “4. 🏷️ fieldControl❗”含义:[formControl] 只能绑定叶子控件(FieldControl),你绑的是 Group / Array。
解决:用 path 定位到叶子字段。
5. 📍 fieldControlBind:[a]->[b]❗
Section titled “5. 📍 fieldControlBind:[a]->[b]❗”含义:路径能查到字段,但该字段没有 form.control。常见于:
- 该字段是
NFCSchema/nonFieldControl()定义的非表单控件 - 路径写错,查到了一个不存在的字段
排查:先打印确认。
非表单控件应该用 [fieldTemplate] 渲染,而不是 [formControl]。
三、布局类问题
Section titled “三、布局类问题”6. 移动视图项失败
Section titled “6. 移动视图项失败”含义:layout({ keyPath }) 指定的目标位置查不到父级。
排查清单:
- 用了
@alias→ 确认对应字段上有setAlias('section') - 用了
..→ 确认层级真的存在,['..','..']已经到顶还会再往上就会失败 - 目标字段是否被
hideWhen/ 条件渲染掉了
layout的完整语义见 API: Layout metadata,路径规则见 API: 路径查询。
四、值与 model 的问题(不报错,但不符合预期)
Section titled “四、值与 model 的问题(不报错,但不符合预期)”7. 输入了内容,model 却不更新
Section titled “7. 输入了内容,model 却不更新”这是设计如此:PiyingView 只在整个表单无错误时才向外发射 modelChange。
所以只要任意字段验证不通过,[(model)] 就不会同步。
想看中间态,改用控件级监听:
或直接拿控件:field.form.control.valueChanges。
8. 禁用字段的值「消失」了
Section titled “8. 禁用字段的值「消失」了”由 disabledValue 策略决定:
disabledValue |
禁用时的行为 |
|---|---|
'reserve'(默认) |
保留值,照常输出 |
'delete' |
不输出该字段的值 |
9. 空数组 / 空对象输出 undefined
Section titled “9. 空数组 / 空对象输出 undefined”给 emptyValue 兜底:
10. 模型里多出来的键被吃掉了
Section titled “10. 模型里多出来的键被吃掉了”由 groupMode 决定(schema 自动推导):
| Schema | groupMode |
多余键 |
|---|---|---|
v.object() |
default |
丢弃 |
v.looseObject() |
loose |
保留 |
v.strictObject() |
strict |
验证失败 |
详见 对象组高级用法。
五、监听类问题
Section titled “五、监听类问题”11. 第一次回调收到 undefined
Section titled “11. 第一次回调收到 undefined”valueChange / hideWhen / disableWhen 初始化时会带初始值触发一次;未设默认值时即为 undefined。
两种解法:
12. 监听不到别的字段
Section titled “12. 监听不到别的字段”['aa'] 查的是当前级别的子级,不是兄弟字段。查同级必须加 ..:
六、JSON Schema 转换类
Section titled “六、JSON Schema 转换类”13. action:[xxx]❗
Section titled “13. action:[xxx]❗”JSON 里写了 actions: [{ "name": "myAction" }],但转换时没注册:
14. 未知类型:xxx
Section titled “14. 未知类型:xxx”type 字段值不在支持列表(string / number / integer / boolean / null / object / array)内。
15. options multi conflict
Section titled “15. options multi conflict”同一处同时表达了单选与多选语义,需去掉冲突的一方。
JSON Schema 的完整限制(互斥模式、嵌套限制、
$ref单文件)见 JSON Schema 支持。
| 手段 | 用法 |
|---|---|
| 看解析结果 | console.log(field.origin) — 保留了解析前的原始数据,仅供调试 |
| 看控件 | field.form.control / field.form.root |
| 看状态 | control.status$$() → 'VALID' | 'INVALID' | 'PENDING' |
| 看错误 | control.errors(PENDING 时为 undefined,属正常) |
| 查字段 | field.get(['..', 'name']) / field.get(['#', 'a', 'b']) |
| 确认类型解析 | 报 🈳define 时,先打印 options.fieldGlobalConfig.types 确认 key |
⚠️
control.errors在异步验证期间返回undefined,别误判成「没有错误」;要区分状态请用status$$()。
- 两种使用模式 — 自动 / 手动模式边界
- 核心概念 — Schema → Field → Component 解析链
- AbstractControl — 值 / 状态 / 验证 API
- 路径查询 —
../#/@alias规则