[Angular ReactiveForm x mat-input] 一つの入力欄のエラーメッセージを出し分ける

  • やりたいこと
    • バリデーションで引っかかった内容毎にエラーメッセージを出し分けて、何を直すべきか?をユーザにリアルタイムで教えたい
    • 入力値に不備がある状態で、ユーザにリクエストをさせない、できない仕組みを作る
  • 同一のフォームで複数のバリデーションルール毎にエラーメッセージを切り替えるには、テンプレート駆動フォームではなく”リアクティブフォーム”の利用が必要

Angularのフォーム テンプレート駆動/Reactive(モデル駆動)

  • フォームの種類
    • テンプレート駆動フォーム
      • フォームの検証ルールをテンプレートとなるhtmlファイルに記載
      • 入力コントロール(Ex. <input>)に属性を付けると、それに対応したFormControlオブジェクトやFormGroupオブジェクトが生成される
      • バリデーション
        • 属性で指定(Ex. required)することで、該当するオブジェクトに適応される
      • 仕組み
        • コンポ―ネントから、オブジェクトにアクセス
    • Reactive(モデル駆動)フォーム
      • テンプレート側で
      • ts側に記載
      • メリット
        • 柔軟なバリデーション、入力されたデータの複雑な制御を実現可能
      • デメリット
        • コードが冗長になりがち
      • 使いどころ
        • 同一のフォーム内で複数のバリデーションルール毎にエラーメッセージを切り替えたいケース
          • Ex. 未入力 or 文字数の不足 or 禁止された入力値の型(大文字禁止なのか等)をユーザにリアルタイムで伝えることでUXの向上を図れる
      • 仕組み
        • コンポーネントにあらかじめFormControlオブジェクトやFormGroupオブジェクトを作っておく
        • テンプレートの入力コントロール(Ex. <input> 要素)からそれらのオブジェクトを参照

実装手順

  • sampleというコンポーネントがあるものとする​
    • sample.component.html
    • sample.component.ts

      モジュールの有効化

  1. app.component.module.tsでReactiveFormsモジュールをimport
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    // Reactive form
    import { ReactiveFormsModule } from '@angular/forms'
    // テンプレート駆動型と同様にFormsModuleも必要

    ~略~

    importts:[

    FormsModule,
    ReactiveFormsModule // 追加
    ]
  2. 対象のコンポーネントでも必要なモジュールをimport
  • sample.component.ts
    1
    import { FormGroup, FormControl, FormBuilder, Validators } from '@angular/forms'
  • FormBuilder
    • 必須ではないが、これを利用すると短く楽に記述できる

      実装例

  • Formbuilderを利用する事で完結に記述した例
  • ID x Password型のシンプルなフォームは基本以下でよさそう
    • 時間を作れればSchematicsで自動生成できるようにしておきます

      #### sample.component.ts
  • Formbuilderをconstructorで注入
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    25
    26
    27
    28
    29
    30
    31
    32
    33
    34
    35
    36
    // 1. import module
    import { FormGroup, FormControl, FormBuilder, Validators } from '@angular/forms'

    export class SampleComponent implements OnInit{

    // 2.1. FormGroup参照用の変数を宣言
    credentialForm:FormGroup;

    // 2.2. FormControl参照用の変数を宣言
    id = new FormControl("", [
    Validators.required,
    Validators.minLength(20)
    ]);
    pass = new FormControl("", [
    Validators.required,
    Validators.minLength(40)
    ]);

    // 3. Formbuilderの注入 FormBuilderオブジェクトを生成
    constructor(private fb: FormBuilder) {
    // 4. FormBuilderオブジェクトを使ってFormGroupとFormControlを作成
    this.credentialForm = this.fb.group({
    // formControlと初期値、バリデート条件を列挙
    id: this.id,
    pass: this.pass
    })
    }

    // リクエスト実行時に入力値を参照するサンプル
    submit(){
    // 入力値の参照
    id = this.id.value.id;
    pass = this.pass.value.pass;
    this.sampleService(id, pass); // 認証機能を持つServiceに送る
    }
    }
  • 入力値の参照
    • this.formControlname.valueで取得可能になっている
      1
      2
      this.id.value;
      this.pass.value;

      sample.component.html

  • 入力コントロールとfonrControlオブジェクトの連携、バリデーションに応じたエラーメッセージの表示
    • maxlengthはhtml側に設定すべき
      • ts側でも検知はできたが、規定した時数以上入力を不可にすることはできなかった為
        1
        2
        3
        4
        5
        6
        7
        8
        9
        10
        11
        12
        13
        14
        15
        16
        17
        18
        19
        20
        21
        22
        23
        24
        25
        26
        27
        28
        29
        30
        31
        32
        33
        34
        35
        36
        37
        38
        39
        40
        41
        42
        43
        <!-- 1. formGroupの設定 -->
        <form [FormGroup] = "credentialForm">

        <mat-form-field>
        <mat-label>accessKeyId</mat-label>

        <!-- 2. FormControlの結びつけ -->
        <input matInput
        formControlName="id"
        placeholder="Ex. XXXXX..."
        maxlength="20">

        <!--&&条件を付けないとエラー解消後もメッセージが残ってしまう為注意-->
        <!-- 3.1. エラーメッセージ 空欄,未入力時 -->
        <mat-error *ngIf="id.invalid && id.invalid.required">入力必須</mat-error>
        <!-- 3.2. エラーメッセージ 文字数不足時 -->
        <materror *ngIf="id.invalid && id.errors.minlength">字数不足</mat-error>

        <!-- 3. FormControlの結びつけ -->
        <mat-form-field>
        <mat-label>Password</mat-label>
        <input matInput
        formControlName="pass"
        placeholder="Ex. FdOI0..."
        maxlength="40"
        [type]="hide ? 'password' : 'text'"
        >
        <!---pattern="[a-zA-Z0-9!-/:-@¥[-`{-~]*"--->
        <!--目のアイコンの押下で入力値の表示を切り替え--->
        <button mat-icon-button
        matSuffix
        (click)="hide = !hide"
        [attr.aria-label]="'Hide password'"
        [attr.aria-pressed]="hide"
        >
        <mat-icon>{{hide ? 'visibility_off' : 'visibility'}}</mat-icon>
        </button>
        <mat-error *ngIf="pass.errors.required">入力必須</mat-error>
        <mat-error *ngIf="pass.errors.minlength">字数不足</mat-error>
        </mat-form-field>

        </form>

  • 送信ボタンの無効化
    • 一つでもバリデーションエラーがあればdisabledで無効化
    • formGroup名.invalid
      • フォームグループ内で一つでもバリデーションエラーがあればtrue
        1
        2
        3
        4
        <button 
        (click)="submit()"
        [disabled]="credentialForm.invalid"
        >送信</button>
  • 他のフォームのバリデーションチェックも条件に加える場合
    • ||でor条件を利用する
      1
      2
      3
      4
      <button mat-raised-button
      (click)="submit()"
      [disabled]="credentialForm.invalid || checkValidation"
      >Get Data</button>

備考

その他

@EventEmitter @Input @Output @ViewChild ACM AMP API Gateway AR AR.js AR.js Studio AWS AWS Amplify AWS Budgets AWS Cost Explorer AWS SDK for JavaScript AddThis Adobe XD Alexa Amazon CloudWatch Amazon Honycode Amazon SNS Android Angular Angular Material AngularFire AppSync Augury C CDN CI/CD Cloud Craft Cloud9 CloudFormation CloudFront CloudTrail Cognito Cost Anomaly Detection Cubase ai Cubasis LE DTM Disqus DynamoDB Elgato HD 60S Firebase Firebase Hosting Former2 Github Github Actions Github.com GithubEnterprise GithubPages Google Chrome Google Cloud Shell GraphQL Hexo Hosting IAM Ionic JSON JavaScript LadioCast Logging LowCode MFA MS Authentication MacBook Pro 16 Mind Node NETDUETTO Netflix Party Netlify Network NoCode Observable PO PdM Promise RPA ReactiveForm Recognition Route53 S3 SAM(Serverless Application Model) SAR SSL SYNCROOM Schematics ScrumInc Serverless Service Siri Sitemap Spark AR Steinberg UR44C Teams Touch Cast Studio Treetable TypeScript UI UI Bakery WAF WAFv2 WEB Page Dev WEB会議 WebAR WebSocketAPI Webhook Windows Power Automate Wireshark aot async/await aws config cloud9 display.land draw.io e2e test filter() forkJoin() google search console hexo-generator-amp iOS iPad Pro iPhone icarus map() mat input mat tree mat-checkbox mat-input mat-selection-list mmhmm ngFor plantUML popIn Aladdin2 then() vscode ”global is not defined” らくがきAR アジャイル アジャイル開発 クロスプラットフォーム ショートカット スクラム スクラム開発 テレワーク ファイル操作 ブラウザ型IDE プロダクトオーナー プロダクトマネージャー プロトタイピング リモートセッション 共同開発 双方向データバインディング 待ち合わせ処理 認定スクラムマスター 静的WEB Hosting 静的WEBサイトHosting
Your browser is out-of-date!

Update your browser to view this website correctly. Update my browser now

×