見出し画像

Angular_ラジオボタンを実装する_mat-radio-button, mat-table, MatTableDataSource.filter #373

ある要素の一覧を動的に取得し、ラジオボタンで選択する機能の実装例です。ラジオボタンは「選択肢の中から1つ選ぶ」ための機能です。

大まかに以下の流れとなります。

  1. mat-radio-groupで選択肢グループを作る

  2. mat-tableで一覧にする

  3. mat-radio-buttonでラジオボタンを作る

  4. mat-form-fieldでMatTableDataSource.filterを使う


mat-radio-groupで選択肢グループを作る

mat-radio-groupで囲まれた範囲のラジオボタンが1つのグループになり、この中から1つ選択することになります。

以下のイメージで使います。

<mat-radio-group>
  <mat-radio-button>
  </mat-radio-button>
</mat-radio-group>


mat-tableで一覧にする

まずTypeScript側でdataSourceという変数に選択肢の要素を格納します。ダイアログを使っているので、呼び出し元からのデータをdataで受け取っています。

MatTableDataSourceに渡している`Enterprise`はインターフェースです。また、mat-tableで表示するためdisplayedColumnsも定義します。

export class SwitchEnterpriseComponent implements OnInit {
  public dataSource: MatTableDataSource<Enterprise>;
  public displayedColumns: string[] = ['select', 'name', 'area'];

  constructor(
    public dialogRef: MatDialogRef<LoginedHeaderComponent>,
    @Inject(MAT_DIALOG_DATA) public data: any
  ) {
    this.dataSource = new MatTableDataSource<Enterprise>(data.enterprises);
  }

htmlで以下のように呼び出します。nameカラムの例です。

<mat-table [dataSource]="dataSource">
  <ng-container matColumnDef="name">
    <th mat-header-cell *matHeaderCellDef>
      エンタープライズ名
    </th>
    <td mat-cell *matCellDef="let enterprise">
      {{ enterprise.name }}
    </td>
  </ng-container>
</mat-table>


mat-radio-buttonでラジオボタンを作る

ラジオボタンは以下のように定義できます。含まれるバリューはmat-tableで扱っているEnterpriseインターフェースのデータです。そのデータをselectEnterprise()という関数に渡しています。

<mat-radio-button [value]="enterprise" (change)="selectEnterprise(enterprise)">
</mat-radio-button>

mat-tableの中で以下のように実装できます。

<mat-table class="switch-enterprise-table" [dataSource]="dataSource">
  <ng-container matColumnDef="select">
    <th mat-header-cell *matHeaderCellDef></th>
    <td mat-cell *matCellDef="let enterprise">
      <mat-radio-button [value]="enterprise" (change)="selectEnterprise(enterprise)">
      </mat-radio-button>
    </td>
  </ng-container>
  <ng-container matColumnDef="name">
    <th mat-header-cell *matHeaderCellDef>
      エンタープライズ名
    </th>
    <td mat-cell *matCellDef="let enterprise">
        {{ enterprise.name }}
    </td>
  </ng-container>
</mat-table>


mat-form-fieldでMatTableDataSource.filterを使う

最後にフィルタリング機能です。mat-tableのフィルタリング機能は、デフォルトではテーブル内に生成されてしまって少し見にくいです。しかしこれをカスタムしてテーブルの外に表示できます。

mat-form-fieldを使うことができます。inputタグを使い、入力された値をapplyFilter()という関数に渡します。

<div class="filter-box">
  <mat-form-field>
    <input
      matInput (input)="applyFilter($event.target['value'])"
      placeholder="エンタープライズをフィルター"
    />
  </mat-form-field>
</div>

applyFilter()は TypeScriptで以下のように定義できます。

  applyFilter(filterValue: string): void {
    this.dataSource.filter = filterValue.trim().toLowerCase();
  }

dataSourceはMatTableDataSourceで定義されていて、filterはその機能です。dataSource.filter に値を設定すると、MatTableDataSource は自動的にその値でフィルタリングを行います。また、デフォルトでデータオブジェクトのすべてのプロパティの値を比較してフィルタリングを行います。

trim()はJavaScriptのStringオブジェクトのメソッドで、文字列の先頭と末尾の空白を削除します。これにより、ユーザーが誤って入力した空白を無視してフィルタリングできます。

フィルタリングはデフォルトで大文字・小文字を区別しないため、toLowerCase() メソッドを使用して入力値を小文字に変換しています。


全体像

最後に、今回の機能の全体像は以下です。

[html]

<div class="filter-box">
  <mat-form-field>
    <input
      matInput (input)="applyFilter($event.target['value'])"
      placeholder="エンタープライズをフィルター"
    />
  </mat-form-field>
</div>
<mat-radio-group class="switch-enterprise-radio-group" [ngModel]="selectedEnterprise">
  <div class="switch-enterprise-enterprise-list">
    <h3>エンタープライズ一覧</h3>
      <mat-table class="switch-enterprise-table" [dataSource]="dataSource" matSort>
        <ng-container matColumnDef="select">
          <th mat-header-cell *matHeaderCellDef></th>
          <td mat-cell *matCellDef="let enterprise">
            <mat-radio-button [value]="enterprise" (change)="selectEnterprise(enterprise)">
            </mat-radio-button>
          </td>
        </ng-container>
        <ng-container matColumnDef="name">
          <th mat-header-cell *matHeaderCellDef mat-sort-header>
            エンタープライズ名
          </th>
          <td mat-cell *matCellDef="let enterprise">
              {{ enterprise.name }}
          </td>
        </ng-container>
        <ng-container matColumnDef="area">
          <th mat-header-cell *matHeaderCellDef mat-sort-header>
            契約エリア
          </th>
          <td mat-cell *matCellDef="let enterprise">
            {{ enterprise.area }}
          </td>
        </ng-container>
        <tr mat-header-row *matHeaderRowDef="displayedColumns"></tr>
        <tr mat-row *matRowDef="let row; columns: displayedColumns"></tr>
      </mat-table>
  </div>
</mat-radio-group>
[TypeScript]

export class SwitchEnterpriseComponent implements OnInit {
  public selectedEnterprise: Enterprise;
  public dataSource: MatTableDataSource<Enterprise>;
  public displayedColumns: string[] = ['select', 'name', 'area'];

  constructor(
    public dialogRef: MatDialogRef<LoginedHeaderComponent>,
    @Inject(MAT_DIALOG_DATA) public data: any
  ) {
    this.dataSource = new MatTableDataSource<Enterprise>(data.enterprises);
  }
  selectEnterprise(enterprise: Enterprise): void {
    this.selectedEnterprise = enterprise;
  }

  applyFilter(filterValue: string): void {
    this.dataSource.filter = filterValue.trim().toLowerCase();
  }
}


ここまでお読みいただきありがとうございました!


参考


いいなと思ったら応援しよう!