reference-signal-forms by angular/angular
npx skills add https://github.com/angular/angular --skill reference-signal-formspackages/forms/signals 目录包含一个实验性的、基于 Signal 的 Angular 表单 API。该系统与现有的响应式表单和模板驱动表单有显著不同。
模型驱动:该系统围绕一个作为单一数据源的 WritableSignal<T> 构建。与响应式表单中 FormControl 持有值不同,这里 Signal 持有值。表单仅仅是该 Signal 的一个视图或投影,并添加了表单特定的状态(有效性、脏状态、触摸状态)。
基于代理的遍历:表单 API (form(signal)) 返回一个 FieldTree。此对象是一个代理。它允许访问嵌套字段(例如 myForm.user.name),而无需手动创建控件组。访问代理上的属性会惰性地解析或创建相应的 。
广告位招租
在这里展示您的产品或服务
触达数万 AI 开发者,精准高效
FieldNode基于模式的逻辑:验证、禁用状态和其他元数据通过模式单独定义。模式使用 apply、applyEach(用于数组)和 applyWhen 等函数应用于表单结构。这将数据的结构与管理它的规则分离开来。
指令作为粘合剂:[formField] 指令将 DOM 元素(原生输入框或自定义控件)绑定到 FieldNode。它处理:
* 在 DOM 和 Signal 之间同步值。
* 将状态(有效、已触摸等)反映到 UI。
* 处理用户交互事件(失去焦点、输入)。
FieldNode (src/field/node.ts)表示表单图中单个字段的核心内部类。它聚合了多个状态管理器:
structure:管理父子关系和 Signal 切片。validationState:计算 valid、invalid、errors 信号。nodeState:跟踪 touched、dirty、pristine。metadataState:存储 min、max、required 等元数据。submitState:跟踪提交状态和服务器错误。ValidationState (src/field/validation.ts)管理验证的复杂性:
submit() 命令式注入的服务器端错误。FormField 指令 (src/directive/form_field_directive.ts)FieldNode 和 DOM 之间的桥梁。
[formField]<input>、<select>、<textarea>。FormUiControl 或 FormValueControl 的组件。ControlValueAccessor 的组件(通过 InteropNgControl)。Schema (src/api/structure.ts & src/api/rules)定义行为。
schema(fn) 创建。apply(path, schema) 应用。required、pattern、min、max)和状态修饰符(disabled、hidden)。form.field.value() 直接从底层 Signal 读取(投影到特定路径)。// 1. 定义模型
const user = signal({name: '', age: 0});
// 2. 定义模式
const userRules = schema((u) => {
required(u.name);
min(u.age, 18);
});
// 3. 创建表单
const userForm = form(user, userRules); // 或者 apply(userForm, userRules)
// 4. 在模板中绑定
// <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_directive.ts:[formField] 指令。[formField] 如何挂接到类型检查和运行时。每周安装量
74
代码仓库
GitHub 星标数
100.1K
首次出现
2026年2月11日
安全审计
安装于
gemini-cli72
github-copilot72
opencode72
kimi-cli71
amp71
codex71
The packages/forms/signals directory contains an experimental, signal-based forms API for Angular. This system differs significantly from the existing Reactive and Template-driven forms.
Model-Driven : The system is built around a WritableSignal<T> which serves as the single source of truth. Unlike Reactive Forms where the FormControl holds the value, here the Signal holds the value. The form is merely a view or projection of that signal, adding form-specific state (validity, dirty, touched).
Proxy-Based Traversal : The form API (form(signal)) returns a FieldTree. This object is a Proxy. It allows accessing nested fields (e.g., myForm.user.name) without manually creating control groups. Accessing a property on the proxy lazily resolves or creates the corresponding FieldNode.
Schema-Based Logic : Validation, disabled state, and other metadata are defined separately via Schemas. Schemas are applied to the form structure using functions like apply, applyEach (for arrays), and applyWhen. This separates the structure of the data from the rules governing it.
Directives as Glue : The [formField] directive binds a DOM element (native input or custom control) to a FieldNode. It handles:
FieldNode (src/field/node.ts)The central internal class representing a single field in the form graph. It aggregates several state managers:
structure: Manages parent/child relationships and signal slicing.validationState: Computes valid, invalid, errors signals.nodeState: Tracks touched, dirty, pristine.metadataState: Stores metadata like min, , .ValidationState (src/field/validation.ts)Manages the complexity of validation:
submit().FormField Directive (src/directive/form_field_directive.ts)The bridge between the FieldNode and the DOM.
[formField]<input>, <select>, <textarea>.FormUiControl or FormValueControl.ControlValueAccessor (via InteropNgControl).Schema (src/api/structure.ts & src/api/rules)Defines the behavior.
schema(fn).apply(path, schema).required, pattern, min, max) and state modifiers (disabled, hidden).form.field.value() reads directly from the underlying signal (projected to the specific path).// 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: Public API entry points (form, apply).packages/forms/signals/src/api/control.ts: Interfaces for custom controls (FormUiControl).packages/forms/signals/src/field/node.ts: The FieldNode implementation.packages/forms/signals/src/directive/form_field_directive.ts: The [formField] directive.[formField] hooks into type-checking and the runtime.Weekly Installs
74
Repository
GitHub Stars
100.1K
First Seen
Feb 11, 2026
Security Audits
Gen Agent Trust HubPassSocketPassSnykPass
Installed on
gemini-cli72
github-copilot72
opencode72
kimi-cli71
amp71
codex71
Flutter应用架构设计指南:分层结构、数据层实现与最佳实践
4,400 周安装
maxrequiredsubmitState: Tracks submission status and server errors.