Angularでリアクティブフォームを使用する方法
序章
Angularは、フォームを操作する2つの方法を提供します。テンプレート駆動型フォームとリアクティブフォーム(モデル駆動型フォームとも呼ばれます)。 テンプレート駆動型フォームは、Angularでフォームを操作するためのデフォルトの方法です。 テンプレート駆動型フォームでは、テンプレートディレクティブを使用してフォームの内部表現を構築します。 リアクティブフォームを使用すると、コンポーネントクラスでフォームの独自の表現を作成できます。
注:リアクティブフォームはAngular2で導入されました。
反応型の利点のいくつかを次に示します。
- カスタムバリデーターの使用
- 検証を動的に変更する
- フォームフィールドを動的に追加する
この記事では、Angularアプリケーションの例にリアクティブフォームを適用する方法について説明します。
前提条件
この記事をフォローしたい場合は、次のものが必要になります。
- Node.jsはローカルにインストールされます。これは、Node.jsのインストール方法とローカル開発環境の作成に従って実行できます。
この投稿は、Angularの基本的な知識があることを前提としています。
この投稿では、@angular/cli
によって生成された新しいAngularプロジェクトからビルドしていることも前提としています。 Angular CLIを使い始めた場合は、この投稿を参照できます。
このチュートリアルは、ノードv15.1.0、npm
v6.14.8、@angular/core
v11.0.0、および@angular/forms
v11.0.0で検証されました。
ステップ1—プロジェクトの設定
このチュートリアルでは、@angular/cli
で生成されたデフォルトのAngularプロジェクトからビルドします。
- npx @angular/cli new angular-reactive-forms-example --style=css --routing=false --skip-tests
これにより、スタイルが「CSS」(「Sass」、「Less」、「Stylus」ではなく)に設定され、ルーティングがなく、テストがスキップされる新しいAngularプロジェクトが構成されます。
新しく作成されたプロジェクトディレクトリに移動します。
- cd angular-reactive-forms-example
リアクティブフォームを操作するには、FormsModule
の代わりにReactiveFormsModule
を使用します。
コードエディタでapp.module.ts
を開き、ReactiveFormsModule
を追加します。
import { BrowserModule } from '@angular/platform-browser';
import { NgModule } from '@angular/core';
import { ReactiveFormsModule } from '@angular/forms';
import { AppComponent } from './app.component';
@NgModule({
declarations: [
AppComponent
],
imports: [
BrowserModule,
ReactiveFormsModule,
],
providers: [],
bootstrap: [AppComponent]
})
export class AppModule { }
この時点で、ReactiveFormsModule
を使用した新しいAngularプロジェクトが作成されているはずです。
ステップ2—コンポーネントテンプレートにフォームを追加する
リアクティブ形式では、ロジックは完全にコンポーネントクラスで宣言されます。
コードエディタでapp.component.html
を開き、次のコード行を追加します。
<form [formGroup]="myForm" (ngSubmit)="onSubmit(myForm)">
<div>
<label>
Name:
<input formControlName="name" placeholder="Your name">
</label>
</div>
<div>
<label>
Email:
<input formControlName="email" placeholder="Your email">
</label>
</div>
<div>
<label>
Message:
<input formControlName="message" placeholder="Your message">
</label>
</div>
<button type="submit">Send</button>
</form>
このコードは、name
、email
、およびmessage
の3つのフィールドを持つフォームを作成します。 "Send"
というラベルの付いた"submit"
ボタンもあります。 フォームを送信すると、メソッドonSubmit(myForm)
が呼び出されます。
注: Angular 2.xを使用している場合は、novalidate
ディレクティブを開始form
タグとともに追加する必要があります。これは、AngularがHTML5の検証をオーバーライドするためです。 Angular 4+では、novalidate
が舞台裏で自動的に追加されます。
それを分解しましょう:
formGroup
:フォームはコンポーネントクラスでFormGroup
として扱われるため、formGroup
ディレクティブを使用するとフォームグループに名前を付けることができます。ngSubmit
:これはフォームの送信時にトリガーされるイベントです。formControlName
:各フォームフィールドには、コンポーネントクラスで使用される名前となる値を持つformControlName
ディレクティブが必要です。
この時点で、フォームを使用するコンポーネントテンプレートを備えた新しいAngularプロジェクトが作成されているはずです。
ステップ3—コンポーネントクラスを構築する
次に、コンポーネントクラスで、FormGroup
内のFormGroup
と個々のFormControl
を定義します。
newing a FormControl
のときに値が指定された場合、その値がフィールドの初期値として使用されます。
FormGroup
とFormControl
の名前がテンプレートで使用されていたものと同じであることに注意してください。 また、ngOnInit
ライフサイクルフックでFormGroup
を初期化する方法にも注意してください。
import { Component, OnInit } from '@angular/core';
import { FormControl, FormGroup } from '@angular/forms';
@Component({
selector: 'app-root',
templateUrl: './app.component.html',
styleUrls: ['./app.component.css']
})
export class AppComponent implements OnInit {
myForm: FormGroup;
ngOnInit() {
this.myForm = new FormGroup({
name: new FormControl('Sammy'),
email: new FormControl(''),
message: new FormControl('')
});
}
onSubmit(form: FormGroup) {
console.log('Valid?', form.valid); // true or false
console.log('Name', form.value.name);
console.log('Email', form.value.email);
console.log('Message', form.value.message);
}
}
このチュートリアルの目的上、onSubmit
メソッドは、送信されたフォーム値を外部のサービスまたはサーバーに実際に伝達しません。 これは、フォームの有効性とFormControl
値にアクセスする方法を示すのに役立ちます。
この時点で、アプリケーションをコンパイルしてWebブラウザーで開くことができます。 name
、email
、message
の値を入力し、送信を押すと、コンソールログに値が表示されます。
手順4—FormBuilder
を使用するようにコンポーネントクラスを更新する
ngOnInit
フォームの構成は、FormBuilder
ヘルパーを使用して書き直すことができます。 これにより、フォームグループとフォームコントロールのすべてのnewingを放棄できます。
コードエディタでapp.component.ts
に戻り、FormControl
を削除して、FormGroup
をFormBuilder
に置き換えます。
import { Component, OnInit } from '@angular/core';
import { FormBuilder, FormGroup } from '@angular/forms';
@Component({
selector: 'app-root',
templateUrl: './app.component.html',
styleUrls: ['./app.component.css']
})
export class AppComponent implements OnInit {
myForm: FormGroup;
constructor(private fb: FormBuilder) {}
ngOnInit() {
this.myForm = this.fb.group({
name: 'Sammy',
email: '',
message: ''
});
}
onSubmit(form: FormGroup) {
console.log('Valid?', form.valid); // true or false
console.log('Name', form.value.name);
console.log('Email', form.value.email);
console.log('Message', form.value.message);
}
}
FormBuilder
を含むこのコードは、FormGroup
を作成するための定型コードの量を減らします。
手順5—Validators
を使用するようにコンポーネントクラスを更新する
Validators
クラスをインポートに追加し、単純な文字列値の代わりに配列を使用してフォームコントロールを宣言します。
配列の最初の値は初期フォーム値であり、2番目の値はバリデーターが使用するためのものです。 複数のバリデーターを配列にラップすることで、同じフォームコントロールで使用できることに注目してください。
コードエディタでapp.component.ts
を再確認し、Validators
を追加します。
import { Component, OnInit } from '@angular/core';
import { FormBuilder, FormGroup, Validators } from '@angular/forms';
@Component({
selector: 'app-root',
templateUrl: './app.component.html',
styleUrls: ['./app.component.css']
})
export class AppComponent implements OnInit {
myForm: FormGroup;
constructor(private fb: FormBuilder) {}
ngOnInit() {
this.myForm = this.fb.group({
name: ['Sammy', Validators.required],
email: ['', [Validators.required, Validators.email]],
message: ['', [Validators.required, Validators.minLength(15)]],
});
}
onSubmit(form: FormGroup) {
console.log('Valid?', form.valid); // true or false
console.log('Name', form.value.name);
console.log('Email', form.value.email);
console.log('Message', form.value.message);
}
}
このコードは、required
をname
、email
、およびmessage
フィールドに追加します。 また、email
値が有効な電子メールアドレスの形式を使用することを保証します。 また、message
値が少なくとも15文字の長さであることを保証します。
これらのフォーム要件のいずれかが合格しない場合、valid
の値はfalse
になります。 これらのフォーム要件がすべて合格している場合、valid
の値はtrue
になります。
ステップ6—テンプレートのフォーム値と有効性へのアクセス
テンプレートでは、各FormControl
の値と有効性、およびフォームグループ全体の値と有効性にアクセスできます。
app.component.html
に再度アクセスし、*ngIf
を使用して、フォームの値が無効な場合にユーザーにフィードバックメッセージを表示します。
<form [formGroup]="myForm" (ngSubmit)="onSubmit(myForm)">
<div>
<label>
Name:
<input formControlName="name" placeholder="Your name">
</label>
<div *ngIf="myForm.get('name').invalid && (myForm.get('name').dirty || myForm.get('name').touched)">
Please provide a name.
</div>
</div>
<div>
<label>
Email:
<input formControlName="email" placeholder="Your email">
</label>
<div *ngIf="myForm.get('email').invalid && (myForm.get('email').dirty || myForm.get('email').touched)">
Please provide a valid email address.
</div>
</div>
<div>
<label>
Message:
<input formControlName="message" placeholder="Your message">
</label>
<div *ngIf="myForm.get('message').invalid && (myForm.get('message').dirty || myForm.get('message').touched)">
Messages must be at least 15 characters long.
</div>
</div>
<button type="submit" [disabled]="myForm.invalid">Send</button>
</form>
このコードは、ユーザーがフィールド(dirty
またはtouched
)を操作したかどうかを確認します。 次に、値が検証要件に合格していない場合は、エラーメッセージが表示されます。 送信ボタンも、フォーム値に関するすべての問題が解決されるまで無効になります。
フォーム制御値を取得する方法は複数あります。 この例では、myForm.controls.name
と同等のmyForm.get('name')
を使用しています。 .hasError('required')
または.errors.required
でエラー情報を取得することができます。
結論
この記事では、Angularアプリケーションの例にリアクティブフォームを適用する方法について説明しました。 FormControl
、FormGroup
、FormBuilder
、およびValidators
を使用して、検証付きのサンプルフォームを作成しました。 その他の機能については、公式ドキュメントを参照してください。
Angularについて詳しく知りたい場合は、Angularトピックページで演習とプログラミングプロジェクトを確認してください。