正確性と完全性を確保するために、ユーザー入力を検証することで、データ品質を全体的に向上させることができます。 このページでは、UIからのユーザー入力を検証し、リアクティブフォームとテンプレート駆動フォームの両方で、役立つ検証メッセージを表示する方法について説明します。
テンプレート駆動フォームでの入力検証
テンプレート駆動フォームに検証を追加するには、ネイティブHTMLフォーム検証の場合と同じように、検証属性を追加します。 Angularは、これらの属性をフレームワーク内のバリデーター関数と一致させるためにディレクティブを使用します。
フォームコントロールの値が変更されるたびに、Angularは検証し、検証エラーのリスト(INVALIDステータスをもたらす)またはnull(VALIDステータスをもたらす)を生成します。
その後、ngModelをローカルテンプレート変数にエクスポートすることで、コントロールの状態を調べることができます。
次の例では、NgModelをnameという変数にエクスポートします。
actor-form-template.component.html (name)
<input
type="text"
id="name"
name="name"
class="form-control"
required
minlength="4"
appForbiddenName="bob"
[(ngModel)]="actor.name"
#name="ngModel"
/>
@if (name.invalid && (name.dirty || name.touched)) {
<div class="alert">
@if (name.hasError('required')) {
<div>Name is required.</div>
}
@if (name.hasError('minlength')) {
<div>Name must be at least 4 characters long.</div>
}
@if (name.hasError('forbiddenName')) {
<div>Name cannot be Bob.</div>
}
</div>
}
例で示されている次の機能に注目してください。
<input>要素には、HTML検証属性(requiredとminlength)があります。 また、カスタムバリデーターディレクティブforbiddenNameもあります。 詳細については、カスタムバリデーターセクションを参照してください。#name="ngModel"は、NgModelをnameというローカル変数にエクスポートします。NgModelは、基になるFormControlインスタンスの多くのプロパティをミラーリングしているため、テンプレート内でこれを使用して、validやdirtyなどのコントロールの状態を確認できます。 コントロールプロパティの完全なリストについては、AbstractControl APIリファレンスを参照してください。最も外側の
@ifは、nameが無効で、コントロールがdirtyまたはtouchedの場合にのみ、ネストされたメッセージのセットを表示します。ネストされた各
@ifは、考えられる検証エラーの1つに対してカスタムメッセージを表示できます。required、minlength、forbiddenNameのメッセージがあります。
HELPFUL: ユーザーがフォームを編集する機会がある前に、バリデーターがエラーを表示しないようにするには、コントロールのdirtyまたはtouched状態のいずれかをチェックする必要があります。
- ユーザーが監視対象のフィールドの値を変更すると、コントロールは「dirty」としてマークされます。
- ユーザーがフォームコントロール要素からフォーカスを外すと、コントロールは「touched」としてマークされます。
リアクティブフォームでの入力検証
リアクティブフォームでは、真実の源はコンポーネントクラスです。 テンプレートで属性を通じてバリデーターを追加する代わりに、コンポーネントクラスのフォームコントロールモデルに直接バリデーター関数を追加します。 その後、Angularは、コントロールの値が変更されるたびにこれらの関数を呼び出します。
バリデーター関数
バリデーター関数は、同期または非同期にできます。
| バリデーターの種類 | 詳細 |
|---|---|
| 同期バリデーター | コントロールインスタンスを受け取り、検証エラーのセットまたはnullをすぐに返す同期関数。FormControlをインスタンス化する際に、第2引数として渡します。 |
| 非同期バリデーター | コントロールインスタンスを受け取り、後で検証エラーのセットまたはnullを発行するPromiseまたはObservableを返す非同期関数。FormControlをインスタンス化する際に、第3引数として渡します。 |
パフォーマンス上の理由から、Angularは、すべての同期バリデーターが合格した場合にのみ非同期バリデーターを実行します。 各バリデーターは、エラーが設定される前に完了する必要があります。
組み込みのバリデーター関数
独自のバリデーター関数を作成したり、Angularの組み込みのバリデーターのいくつかを使用したりできます。
requiredやminlengthなど、テンプレート駆動フォームで属性として使用できるものと同じ組み込みバリデーターはすべて、Validatorsクラスから関数として使用できます。
組み込みのバリデーターの完全なリストについては、Validators APIリファレンスを参照してください。
アクターフォームをリアクティブフォームに更新するには、いくつかの組み込みバリデーターを使用します。 今回は、関数形式で、次の例のようにします。
actor-form-reactive.component.ts (validator functions)
actorForm = new FormGroup({
name: new FormControl(this.actor.name, [
Validators.required,
Validators.minLength(4),
forbiddenNameValidator(/bob/i), // <-- Here's how you pass in the custom validator.
]),
role: new FormControl(this.actor.role),
skill: new FormControl(this.actor.skill, Validators.required),
});
get name() {
return this.actorForm.get('name');
}
get skill() {
return this.actorForm.get('skill');
}
この例では、nameコントロールは、2つの組み込みバリデーター(Validators.requiredとValidators.minLength(4))と、1つのカスタムバリデーターforbiddenNameValidatorを設定しています。
これらすべてのバリデーターは同期であるため、第2引数として渡されます。 関数を配列として渡すことで、複数のバリデーターをサポートできることに注意してください。
この例では、いくつかのゲッターメソッドも追加されています。
リアクティブフォームでは、常に親グループのgetメソッドを通じて任意のフォームコントロールにアクセスできますが、テンプレートの省略形としてゲッターを定義することが便利な場合があります。
name入力のテンプレートをもう一度見ると、テンプレート駆動の例とかなり似ています。
actor-form-reactive.component.html (name with error msg)
<input type="text" id="name" class="form-control" formControlName="name" required />
@if (name.invalid && (name.dirty || name.touched)) {
<div class="alert alert-danger">
@if (name.hasError('required')) {
<div>Name is required.</div>
}
@if (name.hasError('minlength')) {
<div>Name must be at least 4 characters long.</div>
}
@if (name.hasError('forbiddenName')) {
<div>Name cannot be Bob.</div>
}
</div>
}
このフォームは、テンプレート駆動バージョンとは、ディレクティブをエクスポートしなくなった点が異なります。代わりに、コンポーネントクラスで定義されたnameゲッターを使用します。
required属性は、テンプレートにまだ存在することに注意してください。検証には必要ありませんが、アクセシビリティの目的で保持する必要があります。
カスタムバリデーターの定義
組み込みのバリデーターは、アプリケーションのユースケースに常に一致するわけではありません。そのため、カスタムバリデーターを作成する必要がある場合があります。
前の例のforbiddenNameValidator関数を考えてみてください。
その関数の定義は次のようになります。
forbidden-name.directive.ts (forbiddenNameValidator)
/** An actor's name can't match the given regular expression */
export function forbiddenNameValidator(nameRe: RegExp): ValidatorFn {
return (control: AbstractControl): ValidationErrors | null => {
const forbidden = nameRe.test(control.value);
return forbidden ? {forbiddenName: {value: control.value}} : null;
};
}
関数は、_特定の_禁止されている名前を検出するための正規表現を受け取り、バリデーター関数を返すファクトリです。
このサンプルでは、禁止されている名前は「bob」なので、バリデーターは「bob」を含むアクター名をすべて拒否します。 他の場所では、「alice」や、構成された正規表現に一致する名前を拒否できます。
forbiddenNameValidatorファクトリは、構成されたバリデーター関数を返します。
その関数はAngularコントロールオブジェクトを受け取り、コントロール値が有効な場合はnullを返し、_無効な場合は_検証エラーオブジェクトを返します。
検証エラーオブジェクトには通常、検証キーの名前である'forbiddenName'というプロパティと、エラーメッセージに挿入できる任意の値の辞書である{name}という値を持つプロパティがあります。
カスタム非同期バリデーターは同期バリデーターに似ていますが、代わりに後でnullまたは検証エラーオブジェクトを発行するPromiseまたはObservableを返す必要があります。
Observableの場合、Observableは完了する必要があります。その時点で、フォームは最後の発行された値を検証に使用します。
カスタムバリデーターをリアクティブフォームに追加する
リアクティブフォームでは、FormControlに直接関数を渡すことで、カスタムバリデーターを追加します。
actor-form-reactive.component.ts (validator functions)
actorForm = new FormGroup({
name: new FormControl(this.actor.name, [
Validators.required,
Validators.minLength(4),
forbiddenNameValidator(/bob/i), // <-- Here's how you pass in the custom validator.
]),
role: new FormControl(this.actor.role),
skill: new FormControl(this.actor.skill, Validators.required),
});
カスタムバリデーターをテンプレート駆動フォームに追加する
テンプレート駆動フォームでは、テンプレートにディレクティブを追加します。ディレクティブは、バリデーター関数をラップします。
たとえば、対応するForbiddenValidatorDirectiveは、forbiddenNameValidatorのラッパーとして機能します。
Angularは、ディレクティブがNG_VALIDATORSプロバイダーに自身を登録するため、ディレクティブの検証プロセスにおける役割を認識します。次の例に示すように。
NG_VALIDATORSは、拡張可能なバリデーターのコレクションを持つ、定義済みのプロバイダーです。
forbidden-name.directive.ts (providers)
providers: [
{
provide: NG_VALIDATORS,
useExisting: forwardRef(() => ForbiddenValidatorDirective),
multi: true,
},
],
})
export class ForbiddenValidatorDirective implements Validator {
readonly forbiddenName = input<string>('', {alias: 'appForbiddenName'});
validate(control: AbstractControl): ValidationErrors | null {
return this.forbiddenName
? forbiddenNameValidator(new RegExp(this.forbiddenName(), 'i'))(control)
: null;
}
}
その後、ディレクティブクラスはValidatorインターフェースを実装するため、Angularフォームと簡単に統合できます。
以下は、ディレクティブ全体の概要です。
forbidden-name.directive.ts (directive)
@Directive({
selector: '[appForbiddenName]',
providers: [
{
provide: NG_VALIDATORS,
useExisting: forwardRef(() => ForbiddenValidatorDirective),
multi: true,
},
],
})
export class ForbiddenValidatorDirective implements Validator {
readonly forbiddenName = input<string>('', {alias: 'appForbiddenName'});
validate(control: AbstractControl): ValidationErrors | null {
return this.forbiddenName
? forbiddenNameValidator(new RegExp(this.forbiddenName(), 'i'))(control)
: null;
}
}
ForbiddenValidatorDirectiveの準備ができたら、セレクターappForbiddenNameを入力要素に追加して、アクティブ化できます。
たとえば、次のとおりです。
actor-form-template.component.html (forbidden-name-input)
<input
type="text"
id="name"
name="name"
class="form-control"
required
minlength="4"
appForbiddenName="bob"
[(ngModel)]="actor.name"
#name="ngModel"
/>
HELPFUL: カスタム検証ディレクティブがuseExistingではなくuseClassでインスタンス化されていることに注意してください。
登録されたバリデーターは、ForbiddenValidatorDirectiveの_このインスタンス_である必要があります。フォーム内のインスタンスで、forbiddenNameプロパティが「bob」にバインドされています。
useExistingをuseClassに置き換えると、forbiddenNameを持たない新しいクラスインスタンスを登録することになります。
コントロールステータスCSSクラス
Angularは、多くのコントロールプロパティをフォームコントロール要素にCSSクラスとして自動的にミラーリングします。 これらのクラスを使用して、フォームの状態に応じてフォームコントロール要素のスタイルを設定します。 現在サポートされているクラスは次のとおりです。
.ng-valid.ng-invalid.ng-pending.ng-pristine.ng-dirty.ng-untouched.ng-touched.ng-submitted(囲んでいるフォーム要素のみ)
次の例では、アクターフォームは.ng-validと.ng-invalidクラスを使用して、
各フォームコントロールの境界線の色を設定しています。
forms.css (status classes)
.ng-valid[required], .ng-valid.required {
border-left: 5px solid #42A948; /* green */
}
.ng-invalid:not(form) {
border-left: 5px solid #a94442; /* red */
}
.alert div {
background-color: #fed3d3;
color: #820000;
padding: 1rem;
margin-bottom: 1rem;
}
.form-group {
margin-bottom: 1rem;
}
label {
display: block;
margin-bottom: .5rem;
}
select {
width: 100%;
padding: .5rem;
}
クロスフィールド検証
クロスフィールドバリデーターは、フォーム内の異なるフィールドの値を比較し、組み合わせで受け入れるか拒否するカスタムバリデーターです。 たとえば、互いに非互換なオプションを提供するフォームがある場合、ユーザーはAまたはBを選択できますが、両方は選択できません。 フィールドの値によっては、他の値に依存する場合もあります。ユーザーは、Aを選択した場合にのみBを選択できます。
次のクロス検証の例は、次の方法を示しています。
- 2つの兄弟コントロールの値に基づいて、リアクティブまたはテンプレートベースのフォーム入力を検証する
- ユーザーがフォームとやり取りし、検証に失敗した場合に、説明的なエラーメッセージを表示する
これらの例では、クロス検証を使用して、アクターがアクターフォームに記入することで、役割で同じ名前を再利用しないようにしています。 バリデーターは、アクター名と役割が一致しないことを確認することで、これを実現します。
クロス検証をリアクティブフォームに追加する
フォームは、次の構造になっています。
const actorForm = new FormGroup({
'name': new FormControl(),
'role': new FormControl(),
'skill': new FormControl(),
});
nameとroleは兄弟コントロールであることに注意してください。
1つのカスタムバリデーターで両方のコントロールを評価するには、共通の祖先コントロールであるFormGroupで検証する必要があります。
子コントロールを取得するためにFormGroupをクエリして、値を比較します。
FormGroupにバリデーターを追加するには、作成時に第2引数として新しいバリデーターを渡します。
const actorForm = new FormGroup(
{
'name': new FormControl(),
'role': new FormControl(),
'skill': new FormControl(),
},
{validators: unambiguousRoleValidator},
);
バリデーターのコードは次のとおりです。
unambiguous-role.directive.ts
/** An actor's name can't match the actor's role */
export const unambiguousRoleValidator: ValidatorFn = (
control: AbstractControl,
): ValidationErrors | null => {
const name = control.get('name');
const role = control.get('role');
return name && role && name.value === role.value ? {unambiguousRole: true} : null;
};
unambiguousRoleValidatorバリデーターは、ValidatorFnインターフェースを実装しています。
これはAngularコントロールオブジェクトを引数として受け取り、フォームが有効な場合はnullを返し、無効な場合はValidationErrorsを返します。
バリデーターは、FormGroupのgetメソッドを呼び出して子コントロールを取得し、nameコントロールとroleコントロールの値を比較します。
値が一致しない場合、役割は曖昧ではなく、両方が有効で、バリデーターはnullを返します。
値が一致する場合、アクターの役割は曖昧で、バリデーターはエラーオブジェクトを返すことでフォームを無効にする必要があります。
より良いユーザー体験を提供するために、フォームが無効な場合、テンプレートに適切なエラーメッセージが表示されます。
actor-form-template.component.html
@if (actorForm.hasError('unambiguousRole') && (actorForm.touched || actorForm.dirty)) {
<div class="cross-validation-error-message alert alert-danger">
Name cannot match role or audiences will be confused.
</div>
}
この@ifは、FormGroupにunambiguousRoleValidatorバリデーターが返したクロス検証エラーがある場合に、エラーを表示しますが、ユーザーがフォームとやり取りを完了した場合のみです。
クロス検証をテンプレート駆動フォームに追加する
テンプレート駆動フォームの場合、バリデーター関数をラップするディレクティブを作成する必要があります。
次の例に示すように、NG_VALIDATORSトークンを使用して、そのディレクティブをバリデーターとして提供します。
unambiguous-role.directive.ts
@Directive({
selector: '[appUnambiguousRole]',
providers: [
{
provide: NG_VALIDATORS,
useExisting: forwardRef(() => UnambiguousRoleValidatorDirective),
multi: true,
},
],
})
export class UnambiguousRoleValidatorDirective implements Validator {
validate(control: AbstractControl): ValidationErrors | null {
return unambiguousRoleValidator(control);
}
}
新しいディレクティブをHTMLテンプレートに追加する必要があります。
バリデーターはフォームの最上位レベルで登録する必要があるため、次のテンプレートはformタグにディレクティブを配置しています。
actor-form-template.component.html
<form #actorForm="ngForm" appUnambiguousRole>
より良いユーザー体験を提供するために、フォームが無効な場合、適切なエラーメッセージが表示されます。
actor-form-template.component.html
@if (actorForm.hasError('unambiguousRole') && (actorForm.touched || actorForm.dirty)) {
<div class="cross-validation-error-message alert">Name cannot match role.</div>
}
これは、テンプレート駆動フォームとリアクティブフォームの両方で同じです。
非同期バリデーターの作成
非同期バリデーターは、AsyncValidatorFnとAsyncValidatorインターフェースを実装します。
これらは、同期バリデーターと非常に似ており、次の点が異なります。
validate()関数はPromiseまたはObservableを返す必要があります。- 返されるObservableは有限である必要があります。つまり、ある時点で完了する必要があります。
無限のObservableを有限のObservableに変換するには、Observableを
first、last、take、takeUntilなどのフィルタリング演算子でパイプします。
非同期検証は、同期検証の後に実行され、同期検証が成功した場合にのみ実行されます。 このチェックにより、フォームは、基本的な検証方法がすでに無効な入力を検出している場合、潜在的にコストのかかる非同期検証プロセス(HTTPリクエストなど)を回避できます。
非同期検証が開始されると、フォームコントロールはpending状態になります。
コントロールのpendingプロパティを調べ、それを利用して、進行中の検証操作に関する視覚的なフィードバックを提供します。
一般的なUIパターンは、非同期検証の実行中にスピナーを表示することです。 次の例は、テンプレート駆動フォームでこれを実現する方法を示しています。
<input [(ngModel)]="name" #model="ngModel" appSomeAsyncValidator />
@if (model.pending) {
<app-spinner />
}
カスタム非同期バリデーターの実装
次の例では、非同期バリデーターは、アクターがすでに割り当てられている役割にキャストされないようにします。 新しいアクターは常にオーディションを受けており、古いアクターは引退しているため、利用可能な役割のリストを事前に取得はできません。 潜在的な役割のエントリを検証するために、バリデーターは、現在キャストされているすべてのアクターの中央データベースを照会する非同期操作を開始する必要があります。
次のコードは、AsyncValidatorインターフェースを実装するバリデータークラスUniqueRoleValidatorを作成します。
role.directive.ts
@Injectable({providedIn: 'root'})
export class UniqueRoleValidator implements AsyncValidator {
private readonly actorsService = inject(ActorsService);
validate(control: AbstractControl): Observable<ValidationErrors | null> {
return this.actorsService.isRoleTaken(control.value).pipe(
map((isTaken) => (isTaken ? {uniqueRole: true} : null)),
catchError(() => of(null)),
);
}
}
actorsServiceプロパティは、次のインターフェースを定義するActorsServiceトークンのインスタンスで初期化されます。
interface ActorsService {
isRoleTaken: (role: string) => Observable<boolean>;
}
実際のアプリケーションでは、ActorsServiceは、アクターデータベースにHTTPリクエストを送信して役割が利用可能かどうかを確認する役割を担います。
バリデーターの観点から、サービスの実際の実装は重要でないため、例ではActorsServiceインターフェースに対してのみコードを作成できます。
検証が始まると、UniqueRoleValidatorは、現在のコントロール値でActorsServiceのisRoleTaken()メソッドに委任します。
この時点で、コントロールはpendingとしてマークされ、validate()メソッドから返されるObservableチェーンが完了するまで、この状態を維持します。
isRoleTaken()メソッドは、役割が利用可能かどうかを確認するHTTPリクエストをディスパッチし、結果としてObservable<boolean>を返します。
validate()メソッドは、応答をmap演算子でパイプし、検証結果に変換します。
その後、メソッドは、他のバリデーターと同様に、フォームが有効な場合はnullを返し、無効な場合はValidationErrorsを返します。
このバリデーターは、catchError演算子を使用して、潜在的なエラーを処理します。
この場合、バリデーターはisRoleTaken()エラーを正常な検証として扱います。検証リクエストの実行に失敗したとしても、役割が無効であるとは限りません。
エラーを異なる方法で処理し、代わりにValidationErrorオブジェクトを返すこともできます。
しばらくすると、Observableチェーンが完了し、非同期検証が完了します。
pendingフラグはfalseに設定され、フォームの有効性が更新されます。
非同期バリデーターをリアクティブフォームに追加する
リアクティブフォームで非同期バリデーターを使用するには、最初にバリデーターをコンポーネントクラスのプロパティに注入します。
actor-form-reactive.component.2.ts
roleValidator = inject(UniqueRoleValidator);
次に、バリデーター関数をFormControlに直接渡して、適用します。
次の例では、UniqueRoleValidatorのvalidate関数が、roleControlに適用されています。この関数をコントロールのasyncValidatorsオプションに渡し、ActorFormReactiveComponentに注入されたUniqueRoleValidatorのインスタンスにバインドしています。
asyncValidatorsの値は、単一の非同期バリデーター関数、または関数の配列にできます。
FormControlオプションの詳細については、AbstractControlOptions APIリファレンスを参照してください。
actor-form-reactive.component.2.ts
const roleControl = new FormControl('', {
asyncValidators: [this.roleValidator.validate.bind(this.roleValidator)],
updateOn: 'blur',
});
非同期バリデーターをテンプレート駆動フォームに追加する
テンプレート駆動フォームで非同期バリデーターを使用するには、新しいディレクティブを作成し、そのディレクティブにNG_ASYNC_VALIDATORSプロバイダーを登録します。
次の例では、ディレクティブは、実際の検証ロジックを含むUniqueRoleValidatorクラスを注入し、Angularが検証する必要があるときにトリガーするvalidate関数でそれを呼び出します。
role.directive.ts
@Directive({
selector: '[appUniqueRole]',
providers: [
{
provide: NG_ASYNC_VALIDATORS,
useExisting: forwardRef(() => UniqueRoleValidatorDirective),
multi: true,
},
],
})
export class UniqueRoleValidatorDirective implements AsyncValidator {
private readonly validator = inject(UniqueRoleValidator);
validate(control: AbstractControl): Observable<ValidationErrors | null> {
return this.validator.validate(control);
}
}
その後、同期バリデーターと同様に、ディレクティブのセレクターを入力に追加して、アクティブ化します。
actor-form-template.component.html (unique-unambiguous-role-input)
<input
type="text"
id="role"
name="role"
#role="ngModel"
[(ngModel)]="actor.role"
[ngModelOptions]="{updateOn: 'blur'}"
appUniqueRole
/>
非同期バリデーターのパフォーマンスの最適化
デフォルトでは、すべてのバリデーターは、フォームの値が変更されるたびに実行されます。 同期バリデーターの場合、これは通常、アプリケーションのパフォーマンスに目立った影響を与えません。 ただし、非同期バリデーターは通常、コントロールを検証するために何らかのHTTPリクエストを実行します。 キーストロークごとにHTTPリクエストをディスパッチすると、バックエンドAPIに負担がかかる可能性があり、可能な限り回避する必要があります。
updateOnプロパティをchange(デフォルト)からsubmitまたはblurに変更することで、フォームの有効性の更新を遅らせることができます。
テンプレート駆動フォームでは、テンプレートでプロパティを設定します。
<input [(ngModel)]="name" [ngModelOptions]="{updateOn: 'blur'}" />
リアクティブフォームでは、FormControlインスタンスでプロパティを設定します。
new FormControl('', {updateOn: 'blur'});
Managing validators dynamically in reactive forms
In complex reactive forms, you may need to add, remove, or modify validators based on user input or application state.
Angular provides several methods on AbstractControl to manage validators at runtime without recreating form controls.
Adding and removing validators
The addValidators and removeValidators methods allow you to modify a control's validators after initialization.
onCountryChange(country: string) {
const postalCodeControl = this.profileForm.get('postalCode');
if (country === 'US') {
// Add validators for US postal codes
postalCodeControl.addValidators([Validators.required, Validators.pattern(/^\d{5}$/)]);
} else {
// Remove validators when not US
postalCodeControl.removeValidators([Validators.required]);
}
postalCodeControl.updateValueAndValidity();
}
Replacing all validators
Use setValidators to replace all existing synchronous validators on a control, or clearValidators to remove all validators.
toggleStrictNameValidation(isStrict: boolean) {
const nameControl = this.profileForm.get('name');
if (enable) {
// Set strict validation rules
nameControl.setValidators([
Validators.required,
Validators.minLength(3),
Validators.pattern(/^[a-zA-Z]+$/),
]);
} else {
// Clear all validators
nameControl.clearValidators();
}
nameControl.updateValueAndValidity();
}
The same pattern applies to async validators using addAsyncValidators, removeAsyncValidators, setAsyncValidators, and clearAsyncValidators.
Triggering validation updates
After modifying validators, call updateValueAndValidity to recalculate the control's validation status.
This method accepts options to control update behavior.
// Update control and notify parent
control.updateValueAndValidity();
// Update control only, don't notify parent or emit events
control.updateValueAndValidity({onlySelf: true, emitEvent: false});
ネイティブHTMLフォーム検証との相互作用
デフォルトでは、Angularは囲んでいる<form>にnovalidate属性を追加することでネイティブHTMLフォーム検証を無効にし、これらの属性をフレームワーク内のバリデーター関数と一致させるためにディレクティブを使用します。
ネイティブ検証を組み合わせてAngularベースの検証を使用したい場合は、ngNativeValidateディレクティブを使用して、ネイティブ検証を再び有効にできます。
詳細については、APIドキュメントを参照してください。