LoginSignup
0
1

More than 1 year has passed since last update.

Angular フォーム (2):バリデーション

Last updated at Posted at 2021-12-12

バリデーション

フォーム・バリデーションを使う設定は次の通りです。

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>

関連記事

参考資料

0
1
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
0
1