【Angular小ネタ】Mat-Radio-buttonで複数のフォーム表示をコントロールする

この記事は公開されてから1年以上経過しています。情報が古い可能性がありますので、ご注意ください。

どうも、福岡のMeです。
今回はAngular Material のmat-radiobuttonを使ってフォームの切り替えを行いました。 jQueryを使うことなくシンプルに実装できたので、ご紹介したいと思います。

English version of this article is available here.

Outcome

今回作成したものはこちらです。

stackblitz Demo

開発環境

Angular環境は以下の通りです。

$ ng -v

     _                      _                 ____ _     ___
    / \   _ __   __ _ _   _| | __ _ _ __     / ___| |   |_ _|
   / △ \ | '_ \ / _` | | | | |/ _` | '__|   | |   | |    | |
  / ___ \| | | | (_| | |_| | | (_| | |      | |___| |___ | |
 /_/   \_\_| |_|\__, |\__,_|_|\__,_|_|       \____|_____|___|
                |___/


Angular CLI: 6.1.5
Node: 8.11.2
OS: darwin x64
Angular:
...

Package                      Version
------------------------------------------------------
@angular-devkit/architect    0.7.5
@angular-devkit/core         0.7.5
@angular-devkit/schematics   0.7.5
@angular/animations          6.1.4
@angular/cdk                 6.4.6
@angular/cli                 6.1.5
@angular/common              6.1.4
@angular/core                6.1.4
@angular/forms               6.1.4
@angular/material            6.4.6
@schematics/angular          0.7.5
@schematics/update           0.7.5
rxjs                         6.2.2
typescript                   2.9.2

新規プロジェクトの作成

まずは以下のコマンドで新規プロジェクトを作成します。

ng new form-switcher

作成したプロジェクトのディレクトリへ移動します。

cd form-switcher

ng serve -oコマンドで新規プロジェクトが作成されたことを確認しましょう。以下の画面が表示されればOKです。


angular-new-project

次にコンポーネントを新規作成します。以下のコマンドから行って下さい

ng generate component form-switcher.

コンポーネントを作成したら、app.component.htmlのコードを全て削除し、以下のコードに置き換えます。
こうすることによってIndexにform-switcher.component.htmlの内容が表示されるようになります。

<app-form-switcher></app-form-switcher>

使用するモジュールをインストールしmodule.tsへ追加

Mat-radio-button はAngular Material モジュールに含まれるので、npmインストールしておきましょう。

今回は以下のモジュールを使います。
@angular/material
@angular/forms
@angular/platform-browser

インストールが完了したら必要なモジュールをmodule.tsへインポートします。

import { BrowserModule } from '@angular/platform-browser';
import { NgModule } from '@angular/core';

import { AppComponent } from './app.component';
import { FormSwitcherComponent } from './form-switcher/form-switcher.component';

// Reactive Form Module
import { ReactiveFormsModule, FormsModule } from '@angular/forms';

// Radio Button
import {MatRadioModule} from '@angular/material';
import {BrowserAnimationsModule} from '@angular/platform-browser/animations';


@NgModule({
  declarations: [
    AppComponent,
    FormSwitcherComponent
  ],
  imports: [
    BrowserModule,
    ReactiveFormsModule,
    FormsModule,
    MatRadioModule,
    BrowserAnimationsModule
  ],
  providers: [],
  bootstrap: [AppComponent]
})
export class AppModule { }

フォームを作成する

サンプルのフォームを三つ作成します。
今回は複数の検索フォームを作成し、ラジオボタンで表示をコントロールできるようにしました。

フォームの作成にFormBuilderとreactive formを使用します。
divを使って作成することも可能ですが、reactive formには便利なバリデーション機能が含まれているのでお勧めです。

import { Component, OnInit } from '@angular/core';
// Angular Reactive Form
import { FormGroup, FormBuilder, Validators } from '@angular/forms';

@Component({
  selector: 'app-form-switcher',
  templateUrl: './form-switcher.component.html',
  styleUrls: ['./form-switcher.component.css']
})
export class FormSwitcherComponent implements OnInit {

  // Form
  public idSearchForm: FormGroup;
  public keywordSearchForm: FormGroup;
  public emailSearchForm: FormGroup;

  constructor(private fb: FormBuilder) { }

  ngOnInit() {
    this.createForm ();
  }

  createForm () {
    this.idSearchForm = this.fb.group({
      someId: ['', Validators.required]
    });
    this.keywordSearchForm = this.fb.group({
      keyword: ['', Validators.required ]
    });
    this.emailSearchForm = this.fb.group({
      email: ['', Validators.email]
      });
  }
}

フォームのhtmlコードを書きます

<html lang="ja">
  <head>
      <meta charset="utf-8">
      <meta name="viewport" content="width=device-width, initial-scale=1, shrink-to-fit=no">
      <title> Form Switcher Demo</title>
  </head>
  <body>
    <div class="SearchForm">
      <div id='idSearchForm'>
        <div class="center"><h2>ID Search</h2></div>
        <form [formGroup]="idSearchForm" class='form'>
        <div class="form-group">
          <label class="center-block">ID Search
            <input class="form-control" formControlName="someId" placeholder="enter some id here..">
          </label>
        </div>
  
        <button type="submit">
          Search
        </button>
        </form>
      </div><!--End of First Form-->

      <div id='keywordSearchForm'>
        <div class="center"><h2>Keyword Search</h2></div>
        <form [formGroup]="keywordSearchForm" class='form'>
        <div class="form-group">
          <label class="center-block">Keyword Search
            <input class="form-control" formControlName="keyword" placeholder="enter some keyword here..">
          </label>
        </div>
  
        <button type="submit">
          Search
        </button>
        </form>
      </div><!--End of Second Form-->

      <div id='emailSearchForm'>
        <div class="center"><h2>Email Search</h2></div>
        <form [formGroup]="emailSearchForm" class='form'>
        <div class="form-group">
          <label class="center-block">Email Search
            <input class="form-control" formControlName="email" placeholder="Enter email here..">
          </label>
        </div>
        <button type="submit">
          Search
        </button>
        </form>
      </div><!--End of Third Form-->

    </div><!--End of content-->

  </body>
</html>

ラジオボタンを作成します

以下の変数を二つ form-switcher.component.tsに追加しましょう。

  searchTypeSelected: string;
  searchTypes: string[] = ['ID', 'Keyword', 'Email'];

そしてラジオボタンをform-switcher.component.htmlファイルに記述します。

      <mat-radio-group fxFlex fxFlexFill class="searchType-group" [(ngModel)]="searchTypeSelected">
        <mat-radio-button class="searchType" *ngFor="let ty of searchTypes" [value]="ty">
          {{ty}} <br />
        </mat-radio-button>
      </mat-radio-group>

ngIfでフォーム表示のコントロール

ラジオボタンに基づいたフォームが表示されるようngIfを記述します。 これでフォームの切り替えができるようになりました。

<html lang="ja">
  <body>
    <div class="SearchForm">
      <mat-radio-group fxFlex fxFlexFill class="searchType-group" [(ngModel)]="searchTypeSelected">
        <mat-radio-button class="searchType" *ngFor="let ty of searchTypes" [value]="ty">
          {{ty}} <br />
        </mat-radio-button>
      </mat-radio-group>
      <div id='idSearchForm' *ngIf="searchTypeSelected == 'ID'">
        <div class="center"><h2>ID Search</h2></div>
        <form [formGroup]="idSearchForm" class='form'>
        <div class="form-group">
          <label class="center-block">ID Search
            <input class="form-control" formControlName="someId" placeholder="enter some id here..">
          </label>
        </div>
  
        <button type="submit">
          Search
        </button>
        </form>
      </div><!--End of First Form-->

      <div id='keywordSearchForm' *ngIf="searchTypeSelected == 'Keyword'">
        <div class="center"><h2>Keyword Search</h2></div>
        <form [formGroup]="keywordSearchForm" class='form'>
        <div class="form-group">
          <label class="center-block">Keyword Search
            <input class="form-control" formControlName="keyword" placeholder="enter some keyword here..">
          </label>
        </div>
        <button type="submit">
          Search
        </button>
        </form>
      </div><!--End of Second Form-->

      <div id='emailSearchForm' *ngIf="searchTypeSelected == 'Email'">
        <div class="center"><h2>Email Search</h2></div>
        <form [formGroup]="emailSearchForm" class='form'>
        <div class="form-group">
          <label class="center-block">Email Search
            <input class="form-control" formControlName="email" placeholder="Enter email here..">
          </label>
        </div>
  
        <button type="submit">
          Search
        </button>
        </form>
      </div><!--End of Third Form-->

    </div><!--End of content-->

  </body>
</html>

最後に

いかがだったでしょうか。 最近よく使っているAngular Materialは一瞬で完全レスポンシブ、スタイル付きでナビゲーションバーやデータテーブルが作成できたりと可能性の塊なので、これからもいろんな知見を公開していけたらと思っています。

今回のデモ環境は以下のリンクからご覧になれます。 stackblitz.