关于 reference-signal-forms
面向 Angular 开发者的参考技能,介绍 `packages/forms/signals` 中基于 Signals 的表单架构。它说明如何以可写 Signal 保存数据,并通过字段树、Schema、验证和指令提供表单功能。
主要功能
- 01以 Signal 作为数据源
- 02基于 Proxy 访问嵌套字段
- 03Schema 驱动验证与状态
- 04通过 `[formField]` 绑定 DOM
- 05异步错误与提交错误
适用场景
- 01设计由 Signals 驱动的表单
- 02定义嵌套字段的验证规则
- 03绑定原生或自定义控件
- 04处理异步错误或服务端错误
安装
复制下面的命令,在终端中运行。
npx skills add https:/ / github.com/ angular/ angular --skill reference-signal-forms安装后在 Claude Code 中输入/reference-signal-forms确认已加载。
附带文件references/integration.md
详细介绍
Signal Forms 架构
packages/forms/signals 目录包含 Angular 基于信号的表单 API。
此系统与现有的响应式表单和模板驱动表单有显著差异。
思维模型
-
模型驱动:此系统围绕一个
WritableSignal<T>构建,它是唯一数据源。 与由FormControl保存值的响应式表单不同,这里由Signal保存值。 表单只是这个信号的一个_视图_或_投影_,并添加特定于表单的状态(有效性、脏状态、已触碰状态)。 -
基于代理的遍历:表单 API(
form(signal))会返回一个FieldTree。此对象是一个代理。 它允许访问嵌套字段(例如myForm.user.name),而无需手动创建控件组。 访问代理上的属性时,会延迟解析或创建相应的FieldNode。 -
基于 Schema 的逻辑:验证、禁用状态和其他元数据通过 Schema 单独定义。 使用
apply、applyEach(用于数组)和applyWhen等函数,将 Schema 应用到表单结构中。 这将数据的_结构_与管理数据的_规则_分离开来。 -
指令作为粘合层:
[formField]指令将 DOM 元素(原生输入元素或自定义控件)绑定到FieldNode。 它负责:- 在 DOM 与 Signal 之间同步值。
- 将状态(有效、已触碰等)反映到 UI。
- 处理用户交互事件(失焦、输入)。
关键组件
1. FieldNode(src/field/node.ts)
表示表单图中的单个字段的核心内部类。它汇集了多个状态管理器:
structure:管理父子关系和信号切片。validationState:计算valid、invalid、errors信号。nodeState:跟踪touched、dirty和派生的逻辑状态。metadataState:存储min、max、required等元数据。submitState:跟踪提交状态和服务器错误。
2. FieldValidationState(src/field/validation.ts)
实现 ValidationState 并管理验证的复杂性:
- 同步错误:由 Schema 规则派生。
- 异步错误:通过信号处理,包括“待处理”状态。
- 树错误:向上传递或针对特定字段的错误。
- 提交错误:通过
submit()命令式注入的服务器端错误。
3. FormField 指令(src/directive/form_field.ts)
连接 FieldNode 与 DOM 的桥梁。
- 选择器:
[formField] - 支持:
- 原生元素:
<input>、<select>、<textarea>。 - 自定义控件:实现
FormValueControl或FormCheckboxControl的组件。 - 旧版互操作:实现
ControlValueAccessor的组件(通过InteropNgControl)。
- 原生元素:
4. Schema(src/api/structure.ts & src/api/rules)
定义行为。
- 通过
schema(fn)创建。 - 通过
apply(path, schema)应用。 - 规则包括验证器(
required、pattern、min、max)和状态修饰符(disabled、hidden)。
数据流
- 读取:
form.field().value()直接读取底层信号(投影到特定路径)。 - 写入:写入表单(例如通过 UI)会更新底层信号。
- 验证:计算型效果会观察值信号,并运行 Schema 中定义的验证器。
用法示例(概念性)
// 1. Define Model
const user = signal({name: '', age: 0});
// 2. Define Schema
const userRules = schema((u) => {
required(u.name);
min(u.age, 18);
});
// 3. Create Form
const userForm = form(user, userRules); // OR apply(userForm, userRules)
// 4. Bind in Template
// <input [formField]="userForm.name">
重要文件
packages/forms/signals/src/api/structure.ts:公共 API 入口(form、apply)。packages/forms/signals/src/api/control.ts:自定义控件接口(FormUiControl)。packages/forms/signals/src/field/node.ts:FieldNode的实现。packages/forms/signals/src/directive/form_field.ts:[formField]指令。
补充信息
- 编译器与核心集成:详细说明
[formField]如何接入类型检查和运行时。