reference-signal-forms について
`packages/forms/signals` を扱う Angular 開発者向けに、Signal ベースのフォーム構造を解説するリファレンススキルです。書き込み可能な Signal をデータの保持元とし、フィールドツリー、スキーマ、検証、ディレクティブでフォーム機能を構成します。
主な機能
- 01Signal をデータソースとして使用
- 02Proxy によるネストフィールド参照
- 03スキーマ駆動の検証と状態
- 04`[formField]` による DOM バインド
- 05非同期エラーと送信エラー
活用シーン
- 01Signal ベースのフォーム設計
- 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を返します。このオブジェクトは Proxy です。 これにより、コントロールグループを手動で作成せずに、ネストされたフィールド(例:myForm.user.name)にアクセスできます。 プロキシのプロパティにアクセスすると、対応するFieldNodeが遅延的に解決または作成されます。 -
スキーマベースのロジック:バリデーション、無効状態、その他のメタデータは スキーマ によって別途定義されます。 スキーマは、
apply、applyEach(配列用)、applyWhenなどの関数を使ってフォーム構造に適用されます。 これにより、データの 構造 と、それを規定する ルール が分離されます。 -
接着剤としてのディレクティブ:
[formField]ディレクティブは、DOM 要素(ネイティブ入力要素またはカスタムコントロール)をFieldNodeにバインドします。 次の処理を行います。- DOM とシグナル間で値を同期します。
- 状態(有効、操作済みなど)を 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 を実装し、バリデーションの複雑さを管理します。
- 同期エラー:スキーマルールから導出されます。
- 非同期エラー:シグナルを使って処理され、「保留中」状態も含みます。
- ツリーエラー:親へ伝播するエラー、または特定のフィールドを対象とするエラーです。
- 送信エラー:
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 経由)によって、基盤となるシグナルが更新されます。
- バリデーション:計算されたエフェクトが値シグナルを監視し、スキーマで定義されたバリデーターを実行します。
使用例(概念)
// 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]が型チェックとランタイムにどのように連携するかを説明します。