バリデーション
フォーム・バリデーションを使う設定は次の通りです。
1. app.module.ts で、FormsModule をインポートする
2. コンポーネントTSファイルの Validators の importを追加
import { FormGroup, FormBuilder, Validators } from '@angular/forms';
3. コンポーネントTSファイルの ngOnInit() にてフォームコントロール毎にバリデーション・ルールを設定する。
import { Component, OnInit } from '@angular/core';
import { FormGroup, FormBuilder, Validators } from '@angular/forms';
@Component({ 省略 })
export class SampleComponent implements OnInit {
title!:string;
message!:string;
sampleForm!: FormGroup;
constructor(
private formBuilder:FormBuilder
) { }
ngOnInit(): void {
this.title = 'Hello-app';
this.message = 'FormControlを使う';
this.sampleForm = this.formBuilder.group({
name: ['', [Validators.required, Validators.minLength(1)]],
email: ['', [Validators.required, Validators.email]],
age: [0, [Validators.min(1), Validators.max(150)]]
});
}
get name() { return this.sampleForm.get('name'); }
get email() { return this.sampleForm.get('email'); }
get age() { return this.sampleForm.get('age'); }
}
4. コンポネントHTML
<div id="body">
<h1>{{title}}</h1>
<p>メッセージ:{{message}}</p>
<form [formGroup]="sampleForm">
<table>
<tr>
<th>名前:</th>
<td>
<input type="text" formControlName="name">
<ng-container *ngIf="name?.invalid && (name?.dirty || name?.touched)">
<div *ngIf="name?.errors?.['required'] === true" class="error">名前は必須入力です。</div>
</ng-container>
</td>
</tr>
<tr>
<th>Eメール:</th>
<td>
<input type="text" formControlName="email">
<ng-container *ngIf="email?.invalid && (email?.dirty || email?.touched)">
<div *ngIf="email?.errors?.required" class="error">Eメールは必須入力です。</div>
<div *ngIf="email?.errors?.email" class="error">Eメールのフォーマット不正です。</div>
</ng-container>
</td>
</tr>
<tr>
<th>年齢:</th>
<td>
<input type="number" formControlName="age">
<ng-container *ngIf="age?.invalid && (age?.dirty || age?.touched)">
<div *ngIf="age?.errors?.min" class="error">年齢は1才以上でなければなりません。</div>
<div *ngIf="age?.errors?.max" class="error">年齢は150才以下でなければなりません。</div>
</ng-container>
</td>
</tr>
</table>
<input type="button" value="クリック" [disabled]="sampleForm.invalid">
</form>
</div>
- クリックボタンの
[disabled]="sampleForm.invalid"
は、エラーがなければ、使用できるようにするための設定です。
注意点
サンプル通りに記述しているはずなのに、チェック結果を確認する ngIfでコンパイルエラーが発生しました。解決までに時間がかかったのでメモを残しておく。
Error: src/app/sample/sample.component.html:10:59 - error TS2531: Object is possibly 'null'.
10 <div *ngIf="name.invalid && (name.dirty || name.touched)">
~~~~~~~
「name.touch」を「name?.touch」という記述に変えるとエラーが解消されました。この記述だとnullの場合にエラーを回避してくれるようです。
プロパティ宣言で、初期化しないとエディタでエラーになっていました。VS Code に出てくるQuick Fixを使うとエラーが消えました。
- 「Add 'undefined' type to property 'sampleForm'」を選択した場合
sampleForm: FormGroup | undefined;
プロパティ宣言ではエラーは出ないが、参照箇所で undefined の可能性があるのでエラーとなりました。
- 「Add definite assignment assertion to property 'sampleForm:FormGroup'」を選択した場合
sampleForm!:FormGroup
エラーがなくなったので、この定義がベストのようです。
サンプルや書籍とは違い実際はエラーとなる現象は、使っているAngularかNode.jsのバージョンが新しために、TypeScriptのチェックが厳しくなったからなのかも知れないです。
$ ng version
Your global Angular CLI version (13.1.0) is greater than your local version (12.1.4). The local Angular CLI version is used.
To disable this warning use "ng config -g cli.warnings.versionMismatch false".
_ _ ____ _ ___
/ \ _ __ __ _ _ _| | __ _ _ __ / ___| | |_ _|
/ △ \ | '_ \ / _` | | | | |/ _` | '__| | | | | | |
/ ___ \| | | | (_| | |_| | | (_| | | | |___| |___ | |
/_/ \_\_| |_|\__, |\__,_|_|\__,_|_| \____|_____|___|
|___/
Angular CLI: 12.1.4
Node: 16.13.1 (Unsupported)
Package Manager: npm 8.1.2
OS: win32 x64
Angular: 12.1.5
... animations, common, compiler, compiler-cli, core, forms
... platform-browser, platform-browser-dynamic, router
Package Version
---------------------------------------------------------
@angular-devkit/architect 0.1201.4
@angular-devkit/build-angular 12.1.4
@angular-devkit/core 12.1.4
@angular-devkit/schematics 12.1.4
@angular/cli 12.1.4
@schematics/angular 12.1.4
rxjs 6.6.7
typescript 4.3.5
Warning: The current version of Node (16.13.1) is not supported by Angular.
独自バリデーション
メソッド名 (c: FormControl) {
//問題がない場合
return null;
// 問題がある場合
//return { 名前: { valid: boolean値, ... } };
return { 名前: boolean値 };
}
サンプルとして、name に日本語チェックを追加しました。以下は抜粋です。
コンポーネントTSファイル
export class SampleComponent implements OnInit {
ngOnInit(): void {
this.sampleForm = this.formBuilder.group({
name: ['', [Validators.required, this.isJapanese]],
email: ['', [Validators.required, Validators.email]],
age: [0, [Validators.min(1), Validators.max(150)]]
});
}
isJapanese(c: FormControl) {
console.log(JSON.stringify(c.value));
if (c.value == null || c.value == "") {
return null;
}
if (c.value.match(/^[\u30a0-\u30ff\u3040-\u309f\u3005-\u3006\u30e0-\u9fcf]+$/)) {
return null;
}
return { isJapanese: false };
}
}
コンポーネントHTMLファイル
<tr>
<th>名前:</th>
<td>
<input type="text" formControlName="name">
<ng-container *ngIf="name?.invalid && (name?.dirty || name?.touched)">
<div *ngIf="name?.errors?.['required'] === true" class="error">名前は必須入力です。</div>
<div *ngIf="name?.errors?.isJapanese === false" class="error">日本語で入力して下さい。</div>
</ng-container>
</td>
</tr>
関連記事
参考資料
- 『Angular超入門』 著者:掌田 津邪乃
- https://angular.jp/start
- https://angular.jp/guide/form-validation
- https://hepokon365.hatenablog.com/entry/2020/08/23/220835
- https://itblog.verdy-it.xyz/ypescript型宣言字のクエスチョンマークとビックリマ/
- Angularの便利タグng-container, ng-content, ng-template
- javascript 日本語チェックです
- JavaScriptでひらがな・カタカタ・漢字をチェックする方法まとめ