Angularでカスタムフォーム検証を使用する方法
序章
バリデーターは、フォームの値が特定の要件を満たしていることを確認するために使用されます。 これらは、Angularアプリケーションのテンプレート駆動型フォームまたはリアクティブフォームで使用できます。
required
、email
、pattern
、minLength
のようないくつかの組み込みバリデーターがあります。 組み込みのバリデーターでは処理されない機能に対処するカスタムバリデーターを開発することも可能です。
たとえば、電話番号バリデーターは入力フィールドで構成され、値が10桁の長さでない限り有効とは見なされません。
これは、9桁の長さの無効な番号を提供している電話番号入力フィールドのスクリーンショットです。
そして、これは10桁の長さの有効な番号を提供している電話番号入力フィールドのスクリーンショットです。
このチュートリアルでは、Angularアプリケーションの電話番号入力フィールドのカスタムバリデーターを作成します。
前提条件
このチュートリアルを完了するには、次のものが必要です。
- Node.jsはローカルにインストールされます。これは、Node.jsのインストール方法とローカル開発環境の作成に従って実行できます。
- Angularプロジェクトのセットアップにある程度精通している。
このチュートリアルは、ノードv15.2.1、npm
v6.14.8、@angular/core
v11.0.0、および@angular/forms
v11.0.0で検証されました。
プロジェクトの設定
このチュートリアルでは、@angular/cli
で生成されたデフォルトのAngularプロジェクトからビルドします。
- npx @angular/cli new angular-custom-validation-example --style=css --routing=false --skip-tests
注:または、グローバルに@angular/cli
をインストールすることもできます。
これにより、スタイルが「CSS」(「Sass」、「Less」、「Stylus」ではなく)に設定され、ルーティングがなく、テストがスキップされる新しいAngularプロジェクトが構成されます。
新しく作成されたプロジェクトディレクトリに移動します。
- cd angular-custom-validation-example
この時点で、新しいAngularプロジェクトが作成されます。
テンプレート駆動型フォームでのバリデーターの使用
ディレクティブは、テンプレート駆動型フォームでの検証に使用されます。 この例では、@angular/cli
を使用してphone-number-validator
ディレクティブを作成します。
まず、ターミナルを開き、dev依存関係としてインストールされた@angular/cli
パッケージを使用して、新しいディレクティブを生成します。
- ./node_modules/@angular/cli/bin/ng generate directive phone-number-validator
これにより、phone-number-validator.directive.ts
とphone-number-validator.directive.spec.ts
が作成されます。 また、PhoneNumberValidatorDirective
をapp.module.ts
に追加します。
次に、コードエディタでphone-number-validator.directive.ts
を開きます。 Validator
、AbstractControl
、およびNG_VALIDATORS
を追加します。
import { Directive } from '@angular/core';
import { AbstractControl, Validator, NG_VALIDATORS } from '@angular/forms';
@Directive({
selector: '[appPhoneNumberValidator]',
providers: [{
provide: NG_VALIDATORS,
useExisting: PhoneNumberValidatorDirective,
multi: true
}]
})
export class PhoneNumberValidatorDirective implements Validator {
validate(control: AbstractControl) : {[key: string]: any} | null {
if (control.value && control.value.length != 10) {
return { 'phoneNumberInvalid': true };
}
return null;
}
}
このコードは、@angular/forms
のValidator
を実装するディレクティブを作成します。 次の実装方法が必要になります:validate(control: AbstractControl): : {[key: string]: any} | null
。 このバリデーターは、値が10文字の長さに等しくないという条件に失敗した場合、オブジェクト({ 'phoneNumberInvalid': true }
)を返します。 それ以外の場合、値が条件に合格すると、null
が返されます。
次に、ターミナルを開き、dev依存関係としてインストールされた@angular/cli
パッケージを使用して、新しいディレクティブを生成します。
- ./node_modules/@angular/cli/bin/ng generate component template-driven-form-example --flat
このコマンドは、template-driven-form-example.component.ts
およびtemplate-driven-form-example.component.html
ファイルを作成します。 また、TemplateDrivenFormExampleComponent
をapp.module.ts
に追加します。
次に、コードエディタでtemplate-driven-form-example.component.ts
を開き、空の文字列の初期値を使用してphone
を追加します。
import { Component } from '@angular/core';
@Component({
selector: 'app-template-driven-form-example',
templateUrl: './template-driven-form-example.component.html',
styleUrls: ['./template-driven-form-example.component.css']
})
export class TemplateDrivenFormExampleComponent {
phone = '';
}
Angularは、検証関数の戻り値を FormControl / NgModelのerrors
プロパティに追加します。 FormControl
/ NgModel
のerrors
プロパティが空でない場合、フォームは無効です。 errors
プロパティが空の場合、フォームは有効です。
テンプレート駆動型の形式でディレクティブを使用するには、template-driven-form-example.component.html
を開き、次のコードを追加します。
<div class="form-group">
<label>Phone
<input
type="text"
class="form-control"
name="phone"
[(ngModel)]="phone"
#phoneNgModel="ngModel"
appPhoneNumberValidator
[class.is-invalid]="(phoneNgModel.touched || phoneNgModel.dirty) && phoneNgModel.errors?.phoneNumberInvalid"
>
</label>
<span
class="invalid-feedback"
*ngIf="(phoneNgModel.touched || phoneNgModel.dirty) && phoneNgModel.errors?.phoneNumberInvalid"
>
Phone number must be 10 digits
</span>
</div>
このコードは、<input>
要素と<span>
をエラーメッセージとともに作成します。 <input>
要素は、ディレクティブにngModel
およびappPhoneNumberValidator
セレクターを使用します。
<input>
がtouched
またはdirty
であり、検証に合格しなかった場合、2つのことが発生します。 まず、クラスis-invalid
が<input>
に適用されます。 次に、エラーメッセージが表示された<span>
が表示されます。
注:ここにあるクラスの一部(form-group
、form-control
、invalid-feedback
、およびis-valid
)は、ブートストラップフレームワークの一部です。 これらはこのチュートリアルを完了するために必要ではありませんが、フォームに視覚的な美学を提供することができます。
次に、コードエディタでapp.module.ts
を開き、FormModule
を追加します。
import { BrowserModule } from '@angular/platform-browser';
import { NgModule } from '@angular/core';
import { FormsModule } from '@angular/forms';
import { AppComponent } from './app.component';
import { PhoneNumberValidatorDirective } from './phone-number-validator.directive';
import { TemplateDrivenFormExampleComponent } from './template-driven-form-example.component';
@NgModule({
declarations: [
AppComponent
PhoneNumberValidatorDirective,
TemplateDrivenFormExampleComponent
],
imports: [
BrowserModule,
FormsModule
],
providers: [],
bootstrap: [AppComponent]
})
export class AppModule { }
最後に、app.component.html
を開き、コンテンツをTemplateDrivenFormExample
に置き換えます。
<app-template-driven-form-example></app-template-driven-form-example>
npm start
コマンドを実行して、Webブラウザーで入力を操作できます。 電話フィールドに10文字未満または10文字を超える文字を入力すると、エラーメッセージが表示されます。
この時点で、テンプレート駆動型のディレクティブを使用するカスタムバリデーターがあります。
リアクティブフォームでのバリデーターの使用
ディレクティブの代わりに、リアクティブフォームは検証に関数を使用します。
まず、ターミナルを開き、dev依存関係としてインストールされた@angular/cli
パッケージを使用して、新しいディレクティブを生成します。
- ./node_modules/@angular/cli/bin/ng generate component reactive-form-example --flat
このコマンドは、reactive-form-example.component.ts
およびreactive-form-example.component.html
ファイルを作成します。 また、ReactiveFormExampleComponent
をapp.module.ts
に追加します。
次に、コードエディタでreactive-form-example.component.ts
を開き、FormBuilder
とAbstractControl
を追加します。
import { Component, OnInit } from "@angular/core";
import { AbstractControl, FormBuilder, FormGroup } from '@angular/forms';
@Component({
selector: 'app-reactive-form-example',
templateUrl: './reactive-form-example.component.html',
styleUrls: ['./reactive-form-example.component.css']
})
export class ReactiveFormExampleComponent implements OnInit {
myForm: FormGroup;
constructor(private fb: FormBuilder) {}
ngOnInit(): void {
this.myForm = this.fb.group({
phone: ['', [ValidatePhone]]
});
}
saveForm(form: FormGroup) {
console.log('Valid?', form.valid); // true or false
console.log('Phone Number', form.value.phone);
}
}
function ValidatePhone(control: AbstractControl): {[key: string]: any} | null {
if (control.value && control.value.length != 10) {
return { 'phoneNumberInvalid': true };
}
return null;
}
このコードは、ValidatePhone
関数を作成し、それをFormControl
のバリデーター配列に追加します。
コードエディタでreactive-form-example.component.html
を開き、次のフォームを作成します。
<form
class="needs-validation"
novalidate
[formGroup]="myForm"
(ngSubmit)="saveForm(myForm)"
>
<div class="row">
<div class="form-group col-sm-4">
<label>
Phone
<input
type="text"
class="form-control"
formControlName="phone"
[class.is-invalid]="(myForm.get('phone').touched || myForm.get('phone').dirty) && myForm.get('phone').invalid"
>
</label>
<span
class="invalid-feedback"
*ngIf="(myForm.get('phone').touched || myForm.get('phone').dirty) && myForm.get('phone').invalid"
>
Phone number must be 10 digits
</span>
</div>
</div>
</form>
テンプレート駆動型フォームとは異なり、このフォームはform
を備え、[formGroup]
、(ngSubmit)
、formControlName
、およびget
を使用します。
次に、コードエディタでapp.module.ts
を開き、ReactiveFormsModule
を追加します。
import { BrowserModule } from '@angular/platform-browser';
import { NgModule } from '@angular/core';
import { FormsModule, ReactiveFormsModule } from '@angular/forms';
import { AppComponent } from './app.component';
import { PhoneNumberValidatorDirective } from './phone-number-validator.directive';
import { ReactiveFormExampleComponent } from './reactive-form-example.component';
import { TemplateDrivenFormExampleComponent } from './template-driven-form-example.component';
@NgModule({
declarations: [
AppComponent,
PhoneNumberValidatorDirective,
ReactiveFormExampleComponent,
TemplateDrivenFormExampleComponent
],
imports: [
BrowserModule,
FormsModule,
ReactiveFormsModule
],
providers: [],
bootstrap: [AppComponent]
})
export class AppModule { }
最後に、app.component.html
を開き、コンテンツをReactiveFormExample
に置き換えます。
<app-reactive-form-example></app-reactive-form-example>
npm start
コマンドを実行して、Webブラウザーで入力を操作できます。 電話フィールドに10文字未満または10文字を超える文字を入力すると、エラーメッセージが表示されます。
この時点で、リアクティブ形式の関数を使用するカスタムバリデーターがあります。
結論
この記事では、Angularアプリケーションでテンプレート駆動型フォームとリアクティブフォームのカスタム検証を追加する方法を紹介しました。
カスタム検証により、ユーザーから提供された値が期待に適合していることを確認できます。
この投稿の概念をより深く理解するには、プロバイダーに関するこの投稿にアクセスし、AbstractControlについて読んでください。