` にバインドします。
+- `formControlName`:グループ内の名前付きコントロールを入力にバインドします。
+- `formGroupName`:ネストされた `FormGroup` をバインドします。
+- `formArrayName`:ネストされた `FormArray` をバインドします。
+- `[formControl]`:スタンドアロンの `FormControl` をバインドします。
+
+```html
+
+```
+
+## コントロールへのアクセス
+
+特に `FormArray` のコントロールに簡単にアクセスするためのゲッターを使用します。
+
+```ts
+get aliases() {
+ return this.profileForm.get('aliases') as FormArray;
+}
+
+addAlias() {
+ this.aliases.push(this.fb.control(''));
+}
+```
+
+## 値の更新
+
+- `patchValue()`:指定されたプロパティのみを更新します。構造の不一致があっても警告なく無視します。
+- `setValue()`:モデル全体を置き換えます。フォームの構造を厳密に強制します。
+
+```ts
+updateProfile() {
+ this.profileForm.patchValue({
+ firstName: 'Nancy',
+ address: { street: '123 Drew Street' }
+ });
+}
+```
+
+## 統合変更イベント
+
+モダンな Angular(v18+)では、すべてのコントロールに単一の `events` オブザーバブルが提供され、値、ステータス、pristine、touched、リセット、サブミットイベントを追跡できます。
+
+```ts
+import {ValueChangeEvent, StatusChangeEvent} from '@angular/forms';
+
+this.profileForm.events.subscribe((event) => {
+ if (event instanceof ValueChangeEvent) {
+ console.log('New value:', event.value);
+ }
+});
+```
+
+## 手動ステート管理
+
+- `markAsTouched()` / `markAllAsTouched()`:サブミット時にバリデーションエラーを表示するのに便利です。
+- `markAsDirty()` / `markAsPristine()`:値が変更されたかどうかを追跡します。
+- `updateValueAndValidity()`:値とステータスの再計算を手動でトリガーします。
+- ほとんどのメソッドに `{ emitEvent: false }` または `{ onlySelf: true }` オプションを渡して伝播を制御できます。
diff --git a/docs/ja-JP/skills/angular-developer/references/rendering-strategies.md b/docs/ja-JP/skills/angular-developer/references/rendering-strategies.md
new file mode 100644
index 00000000..2688bb10
--- /dev/null
+++ b/docs/ja-JP/skills/angular-developer/references/rendering-strategies.md
@@ -0,0 +1,44 @@
+# レンダリング戦略
+
+Angular は SEO、パフォーマンス、インタラクティビティを最適化するために、複数のレンダリング戦略をサポートしています。
+
+## 1. クライアントサイドレンダリング(CSR)
+
+**デフォルト戦略。** コンテンツはブラウザで完全にレンダリングされます。
+
+- **ユースケース**:インタラクティブなダッシュボード、社内ツール。
+- **メリット**:設定が最もシンプルで、サーバーコストが低い。
+- **デメリット**:SEO が弱く、初期コンテンツの表示が遅い(JS を待つ必要がある)。
+
+## 2. 静的サイト生成(SSG / プリレンダリング)
+
+コンテンツは**ビルド時**に静的 HTML ファイルとして事前にレンダリングされます。
+
+- **ユースケース**:マーケティングページ、ブログ、ドキュメント。
+- **メリット**:最速の初期読み込み、優れた SEO、CDN フレンドリー。
+- **デメリット**:コンテンツ更新のたびに再ビルドが必要で、ユーザー固有のデータには対応できない。
+
+## 3. サーバーサイドレンダリング(SSR)
+
+コンテンツは**初回リクエスト**に対してサーバー上でレンダリングされます。その後のナビゲーションはクライアントサイドで行われます(SPA スタイル)。
+
+- **ユースケース**:EC サイトの商品ページ、ニュースサイト、パーソナライズされた動的コンテンツ。
+- **メリット**:優れた SEO、初期コンテンツの表示が速い。
+- **デメリット**:サーバー(Node.js)が必要で、サーバーコスト/レイテンシが高い。
+
+## ハイドレーション
+
+ハイドレーションは、サーバーレンダリングされた HTML をブラウザでインタラクティブにするプロセスです。
+
+- **フルハイドレーション**:アプリ全体が一度にインタラクティブになります。
+- **インクリメンタルハイドレーション**:(高度)`@defer` ブロックを使用して必要に応じてパーツがインタラクティブになります。
+- **イベントリプレイ**:ハイドレーション完了前に発生したユーザーイベントをキャプチャして再生します。
+
+## 判断マトリックス
+
+| 要件 | 戦略 |
+| :------------------------------ | :------------------- |
+| **SEO + 静的コンテンツ** | SSG |
+| **SEO + 動的コンテンツ** | SSR |
+| **SEO不要 + 高インタラクティビティ** | CSR |
+| **混在** | ハイブリッド(ルートベース) |
diff --git a/docs/ja-JP/skills/angular-developer/references/resource.md b/docs/ja-JP/skills/angular-developer/references/resource.md
new file mode 100644
index 00000000..e6df642c
--- /dev/null
+++ b/docs/ja-JP/skills/angular-developer/references/resource.md
@@ -0,0 +1,77 @@
+# `resource` を使った非同期リアクティビティ
+
+> [!IMPORTANT]
+> `resource` API は現在 Angular で実験的な機能です。
+
+`Resource` は非同期データフェッチを Angular のシグナルベースのリアクティビティに組み込みます。依存関係が変わるたびに非同期ローダー関数を実行し、状態と結果を同期的なシグナルとして公開します。
+
+## 基本的な使い方
+
+`resource` 関数は主に2つのプロパティを持つオプションオブジェクトを受け取ります:
+
+1. `params`:リアクティブな計算(`computed` のようなもの)。ここで読み取られるシグナルが変わると、リソースは再フェッチします。
+2. `loader`:パラメーターに基づいてデータを取得する非同期関数。
+
+```ts
+import { Component, resource, signal, computed } from '@angular/core';
+
+@Component({...})
+export class UserProfile {
+ userId = signal('123');
+
+ userResource = resource({
+ // userId をリアクティブに追跡
+ params: () => ({ id: this.userId() }),
+
+ // params が変わるたびに実行される
+ loader: async ({ params, abortSignal }) => {
+ const response = await fetch(`/api/users/${params.id}`, { signal: abortSignal });
+ if (!response.ok) throw new Error('Network error');
+ return response.json();
+ }
+ });
+
+ // 計算済みシグナル内でリソースの値を使用する
+ userName = computed(() => {
+ if (this.userResource.hasValue()) {
+ return this.userResource.value()?.name;
+ } else {
+ return 'Loading...';
+ }
+ });
+}
+```
+
+## リクエストの中断
+
+前のローダーがまだ実行中に `params` シグナルが変わった場合、`Resource` は提供された `abortSignal` を使って実行中のリクエストを中断しようとします。**`fetch` の呼び出しには常に `abortSignal` を渡してください。**
+
+## データの再読み込み
+
+params を変えずにローダーを強制的に再実行させるには、`.reload()` を呼び出します。
+
+```ts
+this.userResource.reload();
+```
+
+## リソースのステータスシグナル
+
+`Resource` オブジェクトは現在の状態を読み取るためのいくつかのシグナルを提供します:
+
+- `value()`:解決済みデータ、または `undefined`。
+- `hasValue()`:型ガードとなるブール値。値が存在する場合は `true`。
+- `isLoading()`:ローダーが現在実行中かどうかを示すブール値。
+- `error()`:ローダーがスローしたエラー、または `undefined`。
+- `status()`:正確な状態を表す文字列定数(`'idle'`、`'loading'`、`'resolved'`、`'error'`、`'reloading'`、`'local'`)。
+
+## ローカルミューテーション
+
+リソースの値を直接楽観的に更新できます。これにより状態が `'local'` に変わります。
+
+```ts
+this.userResource.value.set({name: 'Optimistic Update'});
+```
+
+## `httpResource` を使ったリアクティブなデータフェッチ
+
+Angular の `HttpClient` を使用している場合は、`httpResource` の使用を優先してください。これはインターセプターを含む Angular の HTTP スタックを活用しながら、同じシグナルベースのリソース API を提供する専用ラッパーです。
diff --git a/docs/ja-JP/skills/angular-developer/references/route-animations.md b/docs/ja-JP/skills/angular-developer/references/route-animations.md
new file mode 100644
index 00000000..ced347b4
--- /dev/null
+++ b/docs/ja-JP/skills/angular-developer/references/route-animations.md
@@ -0,0 +1,56 @@
+# ルートトランジションアニメーション
+
+Angular ルーターは、ルート間のスムーズなビジュアルトランジションのためにブラウザの **View Transitions API** をサポートしています。
+
+## ビュートランジションの有効化
+
+ルーター設定に `withViewTransitions()` を追加します。
+
+```ts
+provideRouter(routes, withViewTransitions());
+```
+
+これは**プログレッシブエンハンスメント**です。API をサポートしていないブラウザでも、ルーターは引き続き動作しますが、トランジションアニメーションは行われません。
+
+## 仕組み
+
+1. ブラウザが古い状態のスクリーンショットを撮ります。
+2. ルーターが DOM を更新します(新しいコンポーネントをアクティベートします)。
+3. ブラウザが新しい状態のスクリーンショットを撮ります。
+4. ブラウザが2つの状態の間をアニメーションします。
+
+## CSS によるカスタマイズ
+
+トランジションは**グローバル CSS ファイル**でカスタマイズします(コンポーネントスコープの CSS ではありません)。
+
+`::view-transition-old()` と `::view-transition-new()` 疑似要素を使用します。
+
+```css
+/* 例:クロスフェード + スライド */
+::view-transition-old(root) {
+ animation: 90ms cubic-bezier(0.4, 0, 1, 1) both fade-out;
+}
+::view-transition-new(root) {
+ animation: 210ms cubic-bezier(0, 0, 0.2, 1) 90ms both fade-in;
+}
+```
+
+## 高度な制御
+
+`onViewTransitionCreated` を使用して、ナビゲーションコンテキストに基づいてトランジションをスキップしたり、動作をカスタマイズしたりします。
+
+```ts
+withViewTransitions({
+ onViewTransitionCreated: ({transition, from, to}) => {
+ // 特定のルートに対してアニメーションをスキップ
+ if (to.url === '/no-animation') {
+ transition.skipTransition();
+ }
+ },
+});
+```
+
+## ベストプラクティス
+
+- **グローバルスタイル**:ビューカプセル化の問題を避けるため、トランジションアニメーションは常に `styles.css` で定義してください。
+- **ビュートランジション名**:ルートをまたいでスムーズにトランジションさせたい要素(ヘッダー画像など)には、一意の `view-transition-name` を割り当ててください。
diff --git a/docs/ja-JP/skills/angular-developer/references/route-guards.md b/docs/ja-JP/skills/angular-developer/references/route-guards.md
new file mode 100644
index 00000000..20ae1a8a
--- /dev/null
+++ b/docs/ja-JP/skills/angular-developer/references/route-guards.md
@@ -0,0 +1,52 @@
+# ルートガード
+
+ルートガードは、ユーザーがルートへ遷移できるか、またはルートから離れられるかを制御します。
+
+## ガードの種類
+
+- **`CanActivate`**:ユーザーはこのルートにアクセスできるか?(例:認証チェック)
+- **`CanActivateChild`**:ユーザーはこのルートの子にアクセスできるか?
+- **`CanDeactivate`**:ユーザーはこのルートから離れられるか?(例:未保存の変更)
+- **`CanMatch`**:このルートはマッチングの対象として考慮すべきか?(例:フィーチャーフラグ)`false` を返すと、ルーターは他のルートのチェックを継続します。
+
+## ガードの作成
+
+Angular 15 以降、ガードは通常、関数として定義します。
+
+```ts
+export const authGuard: CanActivateFn = (route, state) => {
+ const authService = inject(AuthService);
+ const router = inject(Router);
+
+ if (authService.isLoggedIn()) {
+ return true;
+ }
+
+ // ログインページへリダイレクト
+ return router.parseUrl('/login');
+};
+```
+
+## ガードの適用
+
+ルート設定に配列として追加します。順番通りに実行されます。
+
+```ts
+{
+ path: 'admin',
+ component: Admin,
+ canActivate: [authGuard],
+ canActivateChild: [adminChildGuard],
+ canDeactivate: [unsavedChangesGuard]
+}
+```
+
+## 戻り値
+
+- `boolean`:`true` で許可、`false` でブロック。
+- `UrlTree` または `RedirectCommand`:別のルートへリダイレクト。
+- `Observable` または `Promise`:上記の型に解決されます。
+
+## セキュリティに関する注意
+
+**クライアントサイドのガードはサーバーサイドのセキュリティの代わりにはなりません。** サーバー側で常に権限を検証してください。
diff --git a/docs/ja-JP/skills/angular-developer/references/router-lifecycle.md b/docs/ja-JP/skills/angular-developer/references/router-lifecycle.md
new file mode 100644
index 00000000..5f985465
--- /dev/null
+++ b/docs/ja-JP/skills/angular-developer/references/router-lifecycle.md
@@ -0,0 +1,45 @@
+# ルーターのライフサイクルとイベント
+
+Angular ルーターは `Router.events` オブザーバブルを通じてイベントを発行し、開始から終了までのナビゲーションのライフサイクルを追跡できます。
+
+## 主要なルーターイベント(時系列順)
+
+1. **`NavigationStart`**:ナビゲーションが開始されます。
+2. **`RoutesRecognized`**:ルーターが URL をルートにマッチさせます。
+3. **`GuardsCheckStart` / `End`**:`canActivate`、`canMatch` などの評価が行われます。
+4. **`ResolveStart` / `End`**:データ解決フェーズ(リゾルバーによるデータの取得)。
+5. **`NavigationEnd`**:ナビゲーションが正常に完了しました。
+6. **`NavigationCancel`**:ナビゲーションがキャンセルされました(例:ガードが `false` を返した)。
+7. **`NavigationError`**:ナビゲーションが失敗しました(例:リゾルバーでのエラー)。
+
+## イベントのサブスクライブ
+
+`Router` を注入して `events` オブザーバブルをフィルタリングします。
+
+```ts
+import {Router, NavigationStart, NavigationEnd} from '@angular/router';
+
+export class MyService {
+ private router = inject(Router);
+
+ constructor() {
+ this.router.events.pipe(filter((e) => e instanceof NavigationEnd)).subscribe((event) => {
+ console.log('Navigated to:', event.url);
+ });
+ }
+}
+```
+
+## デバッグ
+
+アプリケーション起動時にすべてのルーティングイベントの詳細なコンソールログを有効化します。
+
+```ts
+provideRouter(routes, withDebugTracing());
+```
+
+## よくあるユースケース
+
+- **ローディングインジケーター**:`NavigationStart` が発火したときにスピナーを表示し、`NavigationEnd`/`Cancel`/`Error` で非表示にします。
+- **アナリティクス**:`NavigationEnd` をリッスンしてページビューを追跡します。
+- **スクロール管理**:カスタムスクロール動作のために `Scroll` イベントに応答します。
diff --git a/docs/ja-JP/skills/angular-developer/references/router-testing.md b/docs/ja-JP/skills/angular-developer/references/router-testing.md
new file mode 100644
index 00000000..0fa8fbb4
--- /dev/null
+++ b/docs/ja-JP/skills/angular-developer/references/router-testing.md
@@ -0,0 +1,87 @@
+# RouterTestingHarness を使ったテスト
+
+ルーティングを伴うコンポーネントをテストする場合、**ルーターや関連サービスをモック化しない**ことが重要です。代わりに `RouterTestingHarness` を使用してください。これにより、実際のアプリケーションに近い環境でルーティングロジックをテストするための堅牢で信頼性の高い方法が提供されます。
+
+ハーネスを使用することで、実際のルーター設定、ガード、リゾルバーをテストでき、より意味のあるテストにつながります。
+
+## ルーターテストのセットアップ
+
+`RouterTestingHarness` はルーティングシナリオをテストするための主要なツールです。また、`TestBed` 設定内で `provideRouter` 関数を使ってテスト用ルートを提供する必要があります。
+
+### セットアップ例
+
+```ts
+import {TestBed} from '@angular/core/testing';
+import {provideRouter} from '@angular/router';
+import {RouterTestingHarness} from '@angular/router/testing';
+import {Dashboard} from './dashboard.component';
+import {HeroDetail} from './hero-detail.component';
+
+describe('Dashboard Component Routing', () => {
+ let harness: RouterTestingHarness;
+
+ beforeEach(async () => {
+ // 1. テスト用ルートで TestBed を設定
+ await TestBed.configureTestingModule({
+ providers: [
+ // テスト固有のルートで provideRouter を使用
+ provideRouter([
+ {path: '', component: Dashboard},
+ {path: 'heroes/:id', component: HeroDetail},
+ ]),
+ ],
+ }).compileComponents();
+
+ // 2. RouterTestingHarness を作成
+ harness = await RouterTestingHarness.create();
+ });
+});
+```
+
+### 主要なコンセプト
+
+1. **`provideRouter([...])`**:テスト用のルーティング設定を提供します。テスト対象のコンポーネントが正しく機能するために必要なルートを含める必要があります。
+2. **`RouterTestingHarness.create()`**:ハーネスを非同期で作成・初期化し、ルート URL(`/`)への初回ナビゲーションを実行します。
+
+## ルーターテストの作成
+
+ハーネスを作成したら、ナビゲーションを駆動し、ルーターの状態やアクティベートされたコンポーネントの状態に対してアサーションを行えます。
+
+### 例:ナビゲーションのテスト
+
+```ts
+it('should navigate to a hero detail when a hero is selected', async () => {
+ // 1. 初期コンポーネントにナビゲートし、そのインスタンスを取得
+ const dashboard = await harness.navigateByUrl('/', Dashboard);
+
+ // ダッシュボードにヒーローを選択するメソッドがあると仮定
+ const heroToSelect = {id: 42, name: 'Test Hero'};
+ dashboard.selectHero(heroToSelect);
+
+ // ナビゲーションをトリガーするアクション後の安定を待つ
+ await harness.fixture.whenStable();
+
+ // 2. URL に対してアサート
+ expect(harness.router.url).toEqual('/heroes/42');
+
+ // 3. ナビゲーション後にアクティベートされたコンポーネントを取得
+ const heroDetail = await harness.getHarness(HeroDetail);
+
+ // 4. 新しいコンポーネントの状態に対してアサート
+ expect(await heroDetail.componentInstance.hero.name).toBe('Test Hero');
+});
+
+it('should get the activated component directly', async () => {
+ // 一度にナビゲートしてコンポーネントインスタンスを取得
+ const dashboardInstance = await harness.navigateByUrl('/', Dashboard);
+
+ expect(dashboardInstance).toBeInstanceOf(Dashboard);
+});
+```
+
+### ベストプラクティス
+
+- **ハーネスでナビゲートする**:ナビゲーションをシミュレートするには常に `harness.navigateByUrl()` を使用してください。このメソッドはアクティベートされたコンポーネントのインスタンスで解決される Promise を返します。
+- **ルーターの状態にアクセスする**:`harness.router` を使用してライブのルーターインスタンスにアクセスし、状態に対してアサートします(例:`harness.router.url`)。
+- **アクティベートされたコンポーネントの取得**:現在アクティベートされているルーティングコンポーネントのコンポーネントハーネスインスタンスを取得するには `harness.getHarness(ComponentType)` を、`DebugElement` を取得するには `harness.routeDebugElement` を使用してください。
+- **安定を待つ**:ナビゲーションを引き起こすアクションを実行した後は、アサーションを行う前に必ず `await harness.fixture.whenStable()` でルーティングの完了を待ってください。
diff --git a/docs/ja-JP/skills/angular-developer/references/show-routes-with-outlets.md b/docs/ja-JP/skills/angular-developer/references/show-routes-with-outlets.md
new file mode 100644
index 00000000..c2e558dc
--- /dev/null
+++ b/docs/ja-JP/skills/angular-developer/references/show-routes-with-outlets.md
@@ -0,0 +1,68 @@
+# アウトレットを使ったルートの表示
+
+`RouterOutlet` ディレクティブは、Angularが現在のURLに対応するコンポーネントをレンダリングするためのプレースホルダーです。
+
+## 基本的な使い方
+
+テンプレートに `
` を含めます。Angularはルーティングされたコンポーネントをアウトレットの直後の兄弟要素として挿入します。
+
+```html
+
+
+
+```
+
+## ネストされたアウトレット
+
+子ルートには、親コンポーネントのテンプレート内に独自の `
` が必要です。
+
+```ts
+// 親コンポーネントのテンプレート
+
Settings
+
+```
+
+## 名前付きアウトレット(セカンダリルート)
+
+ページには複数のアウトレットを設定できます。アウトレットに `name` を割り当てることで、特定のアウトレットをターゲットにできます。デフォルト名は `'primary'` です。
+
+```html
+
+
+
+
+```
+
+ルート設定で `outlet` を定義します:
+
+```ts
+{
+ path: 'chat',
+ component: Chat,
+ outlet: 'sidebar'
+}
+```
+
+## アウトレットのライフサイクルイベント
+
+`RouterOutlet` はコンポーネントが変更されるときにイベントを発行します:
+
+- `activate`: 新しいコンポーネントがインスタンス化された。
+- `deactivate`: コンポーネントが破棄された。
+- `attach` / `detach`: `RouteReuseStrategy` と共に使用される。
+
+```html
+
+```
+
+## `routerOutletData` によるデータの受け渡し
+
+`routerOutletData` インプットを使用して、ルーティングされたコンポーネントにコンテキストデータを渡すことができます。コンポーネントはシグナルとして `ROUTER_OUTLET_DATA` インジェクショントークン経由でこのデータにアクセスします。
+
+```ts
+// 親コンポーネント内
+
+
+// ルーティングされたコンポーネント内
+outletData = inject(ROUTER_OUTLET_DATA) as Signal<{ theme: string }>;
+```
diff --git a/docs/ja-JP/skills/angular-developer/references/signal-forms.md b/docs/ja-JP/skills/angular-developer/references/signal-forms.md
new file mode 100644
index 00000000..066be26d
--- /dev/null
+++ b/docs/ja-JP/skills/angular-developer/references/signal-forms.md
@@ -0,0 +1,795 @@
+# シグナルフォーム
+
+シグナルフォームは、対象のAngularバージョンがサポートしている場合、新しいフォームに推奨されます。Angularシグナルを使用して、リアクティブかつ型安全なモデル駆動型のフォーム状態管理を提供します。
+
+シグナルフォームを使用する場合、フィールドの値や型に `null` を使用しないでください。
+
+## インポート
+
+`@angular/forms/signals` から以下をインポートできます:
+
+```ts
+import {
+ form,
+ FormField,
+ submit,
+ // フィールド状態のルール
+ disabled,
+ hidden,
+ readonly,
+ debounce,
+ // スキーマヘルパー
+ applyWhen,
+ applyEach,
+ schema,
+ // カスタムバリデーション
+ validate,
+ validateHttp,
+ validateStandardSchema,
+ // メタデータ
+ metadata,
+} from '@angular/forms/signals';
+```
+
+## フォームの作成
+
+シグナルモデルとともに `form()` 関数を使用します。フォームの構造はモデルから直接導出されます。
+
+```ts
+import {Component, signal} from '@angular/core';
+import {form, FormField} from '@angular/forms/signals';
+
+@Component({
+ // ...
+ imports: [FormField],
+})
+export class Example {
+ // 1. 初期値でモデルを定義する(undefinedは避ける)
+ userModel = signal({
+ name: '', // 重要: 初期値にnullやundefinedは絶対に使用しない
+ email: '',
+ age: 0, // 数値には0を使用し、nullは使用しない
+ address: {
+ street: '',
+ city: '',
+ },
+ hobbies: [] as string[], // 配列には[]を使用し、nullは使用しない
+ });
+
+ // 誤り - このようにしてはいけない:
+ // badModel = signal({
+ // name: null, // エラー: '' を使用すること
+ // age: null, // エラー: 0 を使用すること
+ // items: null // エラー: [] を使用すること
+ // });
+
+ // 2. フォームを作成する
+ userForm = form(this.userModel);
+}
+```
+
+## バリデーション
+
+バリデーターを `@angular/forms/signals` からインポートします。
+
+```ts
+import {required, email, min, max, minLength, maxLength, pattern} from '@angular/forms/signals';
+```
+
+`form()` に渡すスキーマ関数内で使用します:
+
+```ts
+userForm = form(this.userModel, (schemaPath) => {
+ // 必須
+ required(schemaPath.name, {message: 'Name is required'});
+
+ // 条件付き必須
+ required(schemaPath.name, {
+ when({valueOf}) {
+ return valueOf(schemaPath.age) > 10;
+ },
+ });
+ // when は required にのみ使用可能
+ // このようにしてはいけない: pattern(p.name, /xxx/, {when /* ERROR */)
+
+ // メールアドレス
+ email(schemaPath.email, {message: 'Invalid email'});
+
+ // 数値の最小値/最大値
+ min(schemaPath.age, 18);
+ max(schemaPath.age, 100);
+
+ // 文字列/配列の最小長/最大長
+ minLength(schemaPath.password, 8);
+ maxLength(schemaPath.description, 500);
+
+ // パターン(正規表現)
+ pattern(schemaPath.zipCode, /^\d{5}$/);
+});
+```
+
+## FieldState と FormField: 親要素の要件
+
+**FormField**(構造)と **FieldState**(実際のデータ/シグナル)の違いを理解することが重要です。
+
+**ルール**: フィールドを関数として**呼び出す**ことで、そのステートシグナル(valid、touched、dirty、hidden など)にアクセスできます。
+
+```ts
+// f は FormField(構造的)
+const f = form(signal({cat: {name: 'pirojok-the-cat', age: 5}}));
+
+f.cat.name; // FormField: ここからフラグは取得できない!
+f.cat.name.touched(); // エラー: touched() は FormField に存在しない
+
+f.cat.name(); // FieldState: 呼び出すことでシグナルへのアクセスが可能になる
+f.cat.name().touched(); // 有効: シグナルへのアクセス
+f.cat().name.touched(); // エラー: f.cat() はステートであり、子要素を持たない!
+```
+
+テンプレートでも同様です:
+
+```html
+
+@if (bookingForm.hotelDetails.hidden()) { ... }
+
+
+@if (bookingForm.hotelDetails().hidden()) { ... }
+```
+
+## Disabled / Readonly / Hidden
+
+スキーマ内のルールを使用してフィールドのステータスを制御します。
+
+```ts
+import {disabled, readonly, hidden} from '@angular/forms/signals';
+
+userForm = form(this.userModel, (schemaPath) => {
+ // 条件付き無効化
+ disabled(schemaPath.password, ({valueOf}) => !valueOf(schemaPath.createAccount));
+
+ // 条件付き非表示(モデルからは削除せず、非表示としてマークするのみ)
+ hidden(schemaPath.shippingAddress, ({valueOf}) => valueOf(schemaPath.sameAsBilling));
+
+ // 読み取り専用
+ readonly(schemaPath.username);
+});
+```
+
+## バインディング
+
+`FormField` をインポートし、`[formField]` ディレクティブを使用します。
+
+```ts
+import {FormField} from '@angular/forms/signals';
+```
+
+`disabled`、`hidden`、`readonly`、`name` などのステート上のすべてのプロパティは自動的にバインドされます。
+`name` フィールドは手動でバインド_しないでください_。
+
+**重要: 禁止属性**
+`[formField]` を使用する場合、テンプレートで以下の属性を設定してはなりません(静的またはバインドされた形式のいずれも):
+
+- `min`、`max`(代わりにスキーマ内のバリデーターを使用)
+- `value`、`[value]`、`[attr.value]`(`[formField]` によって処理済み)
+- `[attr.min]`、`[attr.max]`
+- `[disabled]`、`[readonly]`(`[formField]` によって処理済み)
+
+このようにしてはいけません: `
` や `
`。
+
+```html
+
+
+
+
+
+
+
+
+
+
+
+```
+
+## リアクティブフォーム
+
+`@angular/forms` から `FormControl`、`FormGroup`、`FormArray`、`FormBuilder` を**インポートしないでください**。シグナルフォームはこれらのコンセプトを完全に置き換えます。
+シグナルフォームにはビルダーがありません。
+
+## ステートへのアクセス
+
+フォーム内の各フィールドは、そのステートを返す関数です。
+
+```ts
+// フィールドを呼び出してアクセスする
+const emailState = this.userForm.email();
+
+// 値(WritableSignal)
+const value = this.userForm().value();
+
+// バリデーションステート(シグナル)
+const isValid = this.userForm().valid();
+const isInvalid = this.userForm().invalid();
+const errors = this.userForm().errors(); // エラーの配列
+const isPending = this.userForm().pending(); // 非同期バリデーション待ち
+
+// インタラクションステート(シグナル)
+const isTouched = this.userForm().touched();
+const isDirty = this.userForm().dirty();
+
+// 可用性ステート(シグナル)
+const isDisabled = this.userForm().disabled();
+const isHidden = this.userForm().hidden();
+const isReadonly = this.userForm().readonly();
+```
+
+重要!: ステートを取得するには、必ずフィールドを呼び出してください。
+
+```ts
+form().invalid()
+form.field().dirty()
+form.field.subfield().touched()
+form.a.b.c.d().value()
+form.address.ssn().pending()
+form().reset()
+
+// 唯一の例外は length です:
+form.children.length
+form.length // 注意: 括弧なし!
+form.client.addresses.length // "()" なし
+
+@for (income of form.addresses; track $index) {/**/}
+```
+
+## 送信
+
+`submit()` 関数を使用します。アクションを実行する前に、すべてのフィールドを自動的にタッチ済みとしてマークします。
+
+**重要**: `submit()` へのコールバックは `async` でなければならず、Promise を返す必要があります。
+
+```ts
+import { submit } from '@angular/forms/signals';
+
+// 正しい - async コールバック
+onSubmit() {
+ submit(this.userForm, async () => {
+ // フォームが有効な場合のみ実行される
+ await this.apiService.save(this.userModel());
+ console.log('Saved!');
+ });
+}
+
+// 誤り - async キーワードが欠けている
+onSubmit() {
+ submit(this.userForm, () => { // エラー: async でなければならない
+ console.log('Saved!');
+ });
+}
+```
+
+## エラー処理
+
+`field().errors()` は ValidationError の配列を返します:
+
+```ts
+interface ValidationError {
+ readonly kind: string;
+ readonly message?: string;
+}
+```
+
+バリデーターから null を返さないでください。
+エラーがない場合は undefined を返してください。
+
+### コンテキスト
+
+`validate()`、`disabled()`、`applyWhen` などのルールに渡される関数は、コンテキストオブジェクトを受け取ります。その構造を理解することが**重要**です:
+
+```ts
+validate(
+ schemaPath.username,
+ ({
+ value, // Signal
: フィールドの現在値(書き込み可能)
+ fieldTree, // FieldTree: サブフィールド(グループ/配列の場合)
+ state, // FieldState: state.valid()、state.dirty() などのフラグへのアクセス
+ valueOf, // (path) => T: 他のフィールドの値を読む(依存関係を追跡)例: valueOf(schemaPath.password)
+ stateOf, // (path) => FieldState: 他のフィールドのステートにアクセス 例: stateOf(schemaPath.password).valid()
+ pathKeys, // Signal: ルートからこのフィールドへのパス
+ }) => {
+ // 誤り: if (touched()) ... (touched はコンテキスト内にない)
+ // 正しい: if (state.touched()) ...
+
+ if (value() === 'admin') {
+ return {kind: 'reserved', message: 'Username admin is reserved'};
+ }
+ },
+);
+```
+
+### 重要: パスはシグナルではない
+
+`form()` コールバック内で、`schemaPath` とその子要素(例: `schemaPath.user.name`)は**シグナルではなく**、**呼び出し可能でもありません**。
+
+```ts
+// 誤り - エラーが発生します:
+applyWhen(p.ssn, () => p.ssn().touched(), (ssnField) => { ... });
+
+// 正しい - stateOf() を使用してパスのステートを取得する:
+applyWhen(p.ssn, ({ stateOf }) => stateOf(p.ssn).touched(), (ssnField) => { ... });
+
+// 正しい - valueOf() を使用してパスの値を取得する:
+applyWhen(p.ssn, ({ valueOf }) => valueOf(p.ssn) !== '', (ssnField) => { ... });
+```
+
+### 複数アイテム
+
+- アイテムごとにルールを適用するには `applyEach` を使用します。
+- **重要**: `applyEach` のコールバックは引数を**1つだけ**取ります(アイテムパス)。2つではありません:
+
+```ts
+// 正しい - 引数1つ
+applyEach(s.items, (item) => {
+ required(item.name);
+});
+
+// 誤り - インデックスを渡さない
+applyEach(s.items, (item, index) => {
+ // エラー: コールバックは引数を1つしか取らない
+ required(item.name);
+});
+```
+
+- テンプレートではアイテムの反復に `@for` を使用します。
+- 配列からアイテムを削除するには、データ内の該当アイテムをそのまま削除してください。
+- **`select` バインディング**: `