シグナルを使ったフォーム
シグナルフォームはAngularのシグナルを基に構築されており、フォームの状態を管理するためのリアクティブで型安全な方法を提供します。
シグナルフォームはAngularのシグナルを使用してフォームの状態を管理し、データモデルとUI間の自動的な同期を提供します。
このガイドでは、シグナルフォームでフォームを作成するための中心的な概念を順を追って説明します。その仕組みは次のとおりです:
最初のフォームを作成する
1. signal()でフォームモデルを作成する
すべてのフォームは、フォームのデータモデルを保持するシグナルを作成することから始まります:
interface LoginData { email: string; password: string;}const loginModel = signal<LoginData>({ email: '', password: '',});
2. フォームモデルをform()に渡してFieldTreeを作成する
次に、フォームモデルをform()関数に渡してフィールドツリーを作成します。これはモデルの形状を反映したオブジェクト構造で、ドット記法でフィールドにアクセスできます:
const loginForm = form(loginModel);// Access fields directly by property nameloginForm.emailloginForm.password
3. [field]ディレクティブでHTML入力をバインドする
次に、[field]ディレクティブを使用してHTMLの入力をフォームにバインドします。これにより、それらの間に双方向バインディングが作成されます:
<input type="email" [field]="loginForm.email" /><input type="password" [field]="loginForm.password" />
その結果、ユーザーによる変更(フィールドへの入力など)は自動的にフォームを更新します。
4. value()でフィールドの値を読み取る
フィールドを関数として呼び出すことで、フィールドの状態にアクセスできます。これにより、フィールドの値、バリデーションステータス、インタラクションの状態に対するリアクティブなシグナルを含むFieldStateオブジェクトが返されます:
loginForm.email() // Returns FieldState with value(), valid(), touched(), etc.
フィールドの現在の値を読み取るには、value()シグナルにアクセスします:
<!-- Render form value that updates automatically as user types --><p>Email: {{ loginForm.email().value() }}</p>
// Get the current valueconst currentEmail = loginForm.email().value();
5. set()でフィールドの値を更新する
value.set()メソッドを使用して、プログラムからフィールドの値を更新できます。これにより、フィールドと基になるモデルシグナルの両方が更新されます:
// Update the value programmaticallyloginForm.email().value.set('[email protected]');
その結果、フィールドの値とモデルシグナルの両方が自動的に更新されます:
// The model signal is also updatedconsole.log(loginModel().email); // '[email protected]'
完全な例は次のとおりです:
基本的な使い方
[field]ディレクティブは、すべての標準的なHTMLのinputタイプで動作します。以下は、最も一般的なパターンです:
テキスト入力
テキスト入力は、さまざまなtype属性やtextareaで動作します:
<!-- Text and email --><input type="text" [field]="form.name" /><input type="email" [field]="form.email" />
数値
数値入力は、文字列と数値を自動的に変換します:
日付と時刻
日付入力は値をYYYY-MM-DD形式の文字列として保存し、時刻入力はHH:mm形式を使用します:
<!-- Date and time - stores as ISO format strings --><input type="date" [field]="form.eventDate" /><input type="time" [field]="form.eventTime" />
日付文字列をDateオブジェクトに変換する必要がある場合は、フィールドの値をDate()に渡すことで変換できます:
const dateObject = new Date(form.eventDate().value());
複数行テキスト
Textareaはテキスト入力と同じように動作します:
<!-- Textarea --><textarea [field]="form.message" rows="4"></textarea>
チェックボックス
チェックボックスはブール値にバインドされます:
<!-- Single checkbox --><label> <input type="checkbox" [field]="form.agreeToTerms" /> I agree to the terms</label>
複数チェックボックス
複数のオプションがある場合は、それぞれに個別のブール値のfieldを作成します:
<label> <input type="checkbox" [field]="form.emailNotifications" /> Email notifications</label><label> <input type="checkbox" [field]="form.smsNotifications" /> SMS notifications</label>
ラジオボタン
ラジオボタンはチェックボックスと同様に動作します。ラジオボタンが同じ[field]値を使用している限り、シグナルフォームは自動的に同じname属性をすべてのラジオボタンにバインドします:
<label> <input type="radio" value="free" [field]="form.plan" /> Free</label><label> <input type="radio" value="premium" [field]="form.plan" /> Premium</label>
ユーザーがラジオボタンを選択すると、フォームのfieldにはそのラジオボタンのvalue属性の値が保存されます。例えば、「Premium」を選択すると、form.plan().value()は"premium"に設定されます。
selectドロップダウン
Select要素は、静的オプションと動的オプションの両方で動作します:
<!-- Static options --><select [field]="form.country"> <option value="">Select a country</option> <option value="us">United States</option> <option value="ca">Canada</option></select><!-- Dynamic options with @for --><select [field]="form.productId"> <option value="">Select a product</option> @for (product of products; track product.id) { <option [value]="product.id">{{ product.name }}</option> }</select>
NOTE: 複数選択(<select multiple>)は、現時点では[field]ディレクティブでサポートされていません。
バリデーションと状態
シグナルフォームには、フォームフィールドに適用できる組み込みのバリデーターが用意されています。バリデーションを追加するには、form()の第2引数にスキーマ関数を渡します。この関数は、フォームモデル内のフィールドを参照できるスキーマパスパラメーターを受け取ります:
const loginForm = form(loginModel, (schemaPath) => { debounce(schemaPath.email, 500); required(schemaPath.email); email(schemaPath.email);});
NOTE: スキーマパスパラメーターは、バリデーションルールを適用するためのフィールドへのパスを提供します。フィールドの値と状態にアクセスするには、フィールドツリー(loginForm.email()など)を使用してください。
一般的なバリデーターには次のものがあります:
required()- フィールドに値があることを保証しますemail()- メール形式を検証しますmin()/max()- 数値の範囲を検証しますminLength()/maxLength()- 文字列またはコレクションの長さを検証しますpattern()- 正規表現パターンに対して検証します
バリデーターの第2引数にオプションオブジェクトを渡すことで、エラーメッセージをカスタマイズできます:
required(schemaPath.email, { message: 'Email is required' });email(schemaPath.email, { message: 'Please enter a valid email address' });
各フォームフィールドは、シグナルを通じてそのバリデーション状態を公開します。たとえば、field().valid()をチェックしてバリデーションが成功したか、field().touched()をチェックしてユーザーが操作したかを確認し、field().errors()をチェックしてバリデーションエラーのリストを取得できます。
以下に完全な例を示します:
フィールドの状態シグナル
すべてのfield()は、これらの状態シグナルを提供します:
| 状態 | 説明 |
|---|---|
valid() |
フィールドがすべてのバリデーションルールをパスした場合にtrueを返します |
touched() |
ユーザーがフィールドにフォーカスしてぼかした場合にtrueを返します |
dirty() |
ユーザーが値を変更した場合にtrueを返します |
disabled() |
フィールドが無効になっている場合にtrueを返します |
pending() |
非同期バリデーションが進行中の場合にtrueを返します |
errors() |
kindとmessageプロパティを持つバリデーションエラーの配列を返します |
TIP: debounce()バリデーションルールを使用して、ユーザーが入力を停止するかフィールドを離れるまでエラー表示を遅延させます。これにより、ユーザーがまだ入力中にエラーが表示されるのを防ぎます。