4
0

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?

Angular入門 ~ FormsModule編

Posted at

概要

Angularで個人的に一番よく使っているFormsModuleを用いた入力管理の方法を入門レベルでまとめました。

プロジェクト全体のソースコードはこちらに置いてあります。
https://github.com/ist-h-i/Angular/tree/main/v-18

環境設定

node -v

v20.17.0

ng version

Package | Version
— | ---
@angular-devkit/architect | 0.1802.6
@angular-devkit/build-angular | 18.2.6
@angular-devkit/core | 18.2.6 (cli-only)
@angular-devkit/schematics | 18.2.6
@schematics/angular | 18.2.6
rxjs | 7.8.1
typescript | 5.5.4
zone.js | 0.14.10

初期構築コマンド

Angularインストール

npm install -g @angular/cli

プロジェクト作成

ng new “アプリ名”

コンポーネント作成

ng g c components/”コンポーネント名”

node-modulesインストール

npm i

アプリ起動

npm start

実装

上記手順でformsコンポーネントを作成しています。

forms.component.html

<form [formGroup]="myForm">
    <!-- formArrayName="items"で、FormArray("items")を指定 -->
    <div formArrayName="items">
        <!-- items.controlsをループして、各FormControlを表示 -->
        @for (item of items.controls; track $index) {
        <div>
            <!-- FormControlのvalueに紐づくinputを表示 -->
            <input [formControlName]="$index" type="text">
        </div>
        <!-- FormControlのエラーメッセージを表示 -->
        @if (item.invalid && (item.dirty || item.touched)) {
        <div>
            <!-- requiredエラーの場合 -->
            @if (item.errors?.['required']) {
            <div>入力してください</div>
            }
            <!-- minlengthエラーの場合 -->
            @if (item.errors?.['minlength']) {
            <div>最低文字数は{{ item.errors?.['minlength'].requiredLength }}文字です</div>
            }
        </div>
        }
        }
    </div>
    <!-- FormArrayのエラーメッセージを表示 -->
    @if (items.invalid && (items.dirty || items.touched)) {
    <div>
        <!-- atLeastOneItemエラーの場合 -->
        @if (items.errors?.['atLeastOneItem']) {<div>1つ以上の項目を入力してください</div>}
    </div>
    }
    <!-- 追加ボタン -->
    <button (click)="addItem()">追加</button>
    <!-- 削除ボタン -->
    <button (click)="removeItem()">削除</button>
</form>

forms.component.ts

import { Component } from '@angular/core';
import { FormGroup, FormArray, FormControl, ReactiveFormsModule, Validators, AbstractControl, ValidationErrors } from '@angular/forms';
import { ValidatorFn } from '@angular/forms';

/**
 * formArrayを使用して複数のフォームコントロールを生成する
 * formArrayの長さが0の場合、atLeastOneItemValidatorによってエラーを返す
 */
@Component({
  selector: 'app-forms',
  standalone: true,
  imports: [
    ReactiveFormsModule
  ],
  templateUrl: './forms.component.html',
  styleUrl: './forms.component.scss'
})

export class FormsComponent {

  myForm: FormGroup;

  /**
   * formArrayを取得する
   */
  get items(): FormArray {
    return this.myForm.get('items') as FormArray;
  }

  /**
   * constructor
   */
  constructor() {
    /**
     * formArrayを生成する
     * formArrayの長さが0の場合、atLeastOneItemValidatorによってエラーを返す
     */
    this.myForm = new FormGroup({
      items: new FormArray([], this.atLeastOneItemValidator())
    });
  }

  /**
   * formArrayに新しいFormControlを追加
   *
   * @remarks
   *  - FormControlのvalueは空文字列
   *  - FormControlにはrequiredとminLength(3)のValidatorを追加
   */
  addItem(): void {
    this.items.push(new FormControl(
      '',
      [
        Validators.required,
        Validators.minLength(3)
      ]
    ));
  }

  /**
   * formArrayの最後尾のFormControlを削除
   */
  removeItem(): void {
    this.items.removeAt(this.items.length - 1);
  }

  /**
   * formArrayの長さが0の場合、atLeastOneItemValidatorによってエラーを返す
   * @param control formArray
   * @returns null or { atLeastOneItem: true }
   */
  private atLeastOneItemValidator(): ValidatorFn {
    return (control: AbstractControl): ValidationErrors | null => {
      const formArray = control as FormArray;
      return formArray.controls.length > 0 ? null : { atLeastOneItem: true };
    };
  }
}

まとめ

今回はAngular入門第一弾としてよく使っているFormsでの入力管理をまとめてみました。
FormArrayやカスタムバリデータを使えると実装に幅が出ていろいろな状況で使えますね。
注意事項としてFormsは双方向バインディングのngModelと相性が悪いです。(前提として片方で事足りる場合がほとんどで、併用しないといけない状況が思い浮かばないですが下のおまけに併用方法を残しておきます。)
次回はAngularバージョン18で安定板になったzonelessでのsignalを用いた画面への変更反映をまとめる予定です。

おまけ

Angular 14以降では、ngModelとFormGroupを併用するためのオプションが提供されています。
具体的には、ngModelOptionsディレクティブを使用して、ngModelとFormGroupを併用するための設定を指定できます。
次の例は、ngModelOptionsディレクティブを使用して、ngModelとFormGroupを併用する方法を示しています。

<form [formGroup]="myForm">
  <input formControlName="name" [(ngModel)]="user.name" [ngModelOptions]="{ standalone: true }">
</form>
4
0
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
4
0

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?