Angular Materialのセレクトボックスにフィルタリング機能を付ける

はじめに

Angular Materialで用意されているセレクトボックスにはフィルタリング機能がありません。
しかし、カスタマイズをすることで簡単にフィルタリング機能を付けることができます。
今回はその一例をご紹介したいと思います。

環境

  • Angular 9.1.11
  • Angular CLI 9.1.9
  • Angular Material 9.2.4

前提

  • Angular CLIでプロジェクトを作成済み
  • Angular Materialをプロジェクトに導入済み

コンポーネントを作成する

実装を進めていくためのコンポーネントを作成します。
プロジェクトフォルダに移動して、下記のコマンドを実行してください。
今回はsampleという名前のコンポーネントを作成します。

ng g c sample

セレクトボックスにフィルタリング機能を付ける

まずは、ロジック部分を実装していきます。
src/app/sample/sample.component.tsを開き、下記の通りに修正してください。
フィルタリングの処理自体はfilteringSelectBoxOptionsメソッドに記述した一文のみです。

import {Component, OnInit} from '@angular/core';

interface SelectBoxOption {
  text: string;
  value: number;
}

@Component({
  selector: 'app-sample',
  templateUrl: './sample.component.html',
  styleUrls: ['./sample.component.css']
})
export class SampleComponent implements OnInit {
  displaySelectBoxOptions: SelectBoxOption[]; // 表示用のセレクトボックスのオプション
  selectedVal: number;                        // セレクトボックスで選択したオプションのvalue
  inputFilteringVal: string;                  // フィルタリングの条件となる値

  constructor() {
  }

  /**
   * コンポーネント生成時の初期化処理
   */
  ngOnInit(): void {
    this.initSelectBox();
  }

  /**
   * セレクトボックスの初期化処理
   */
  initSelectBox(): void {
    this.displaySelectBoxOptions = this.getOriginalSelectBoxOptions();
    this.inputFilteringVal = '';
  }

  /**
   * オリジナルのセレクトボックスのオプションを取得
   */
  getOriginalSelectBoxOptions(): SelectBoxOption[] {
    return [
      {text: 'Angular', value: 1},
      {text: 'React', value: 2},
      {text: 'Vue.js', value: 3},
      {text: 'Riot.js', value: 4},
    ];
  }

  /**
   * セレクトボックスのオプションをフィルタリングする
   */
  filteringSelectBoxOptions(): void {
    this.displaySelectBoxOptions =
      this.getOriginalSelectBoxOptions()
        .filter(option => option.text.indexOf(this.inputFilteringVal) >= 0);
  }
}

次にビューを実装していきます。
src/app/sample/sample.component.htmlを開き、下記の通りに修正してください。

<mat-form-field class="filtering-select-box">
  <mat-label>JS Framework&Library</mat-label>
  <mat-select (closed)="initSelectBox()" [(ngModel)]="selectedVal">
    <mat-optgroup>
      <mat-form-field class="input-filtering-field">
        <input matInput type="text" placeholder="フィルタリングの条件入力"
               [(ngModel)]="inputFilteringVal"
               (keyup)="filteringSelectBoxOptions()"
               autocomplete="off">
      </mat-form-field>
      <mat-option *ngFor="let option of displaySelectBoxOptions" [value]="option.value">
        {{option.text}}
      </mat-option>
    </mat-optgroup>
  </mat-select>
</mat-form-field>

最後にレイアウトを調整します。
(フィルタリング機能の実装には直接関係が無いため、レイアウトの調整は飛ばしても問題ありません。)
src/app/sample/sample.component.cssを開き、下記の通りに修正してください。

.filtering-select-box {
  width: 200px;
}
.input-filtering-field {
  width: 100%;
}

以上で実装は完了です。

今回作成したコンポーネントを表示するための設定

src/app/app.component.htmlを開き、下記のタグを追加してください。

<app-sample></app-sample>

次にsrc/app/app.module.tsを開き、下記のコメント部分を追加してください。

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

import {AppComponent} from './app.component';
import {BrowserAnimationsModule} from '@angular/platform-browser/animations';
import {SampleComponent} from './sample/sample.component';

// ここから下のimport文を追加する
import {MatFormFieldModule} from '@angular/material/form-field';
import {MatSelectModule} from '@angular/material/select';
import {MatInputModule} from '@angular/material/input';
import {FormsModule} from '@angular/forms';

@NgModule({
  declarations: [
    AppComponent,
    SampleComponent
  ],
  imports: [
    BrowserModule,
    BrowserAnimationsModule,

    // ここから下のモジュールを追加する
    MatFormFieldModule,
    MatSelectModule,
    MatInputModule,
    FormsModule,
  ],
  providers: [],
  bootstrap: [AppComponent]
})
export class AppModule {
}

以上で設定は完了です。

動作確認

最後に下記のコマンドを実行して動作確認をします。

# ビルドとサーバの起動、ブラウザの表示を自動で行う
ng s -o

入力した条件でセレクトボックスのオプションがフィルタリングされているのが確認できます。

まとめ

フィルタリングの処理自体はfilteringSelectBoxOptionsメソッドに記述した一文だけです。ビューについてもセレクトボックス内にフィルタリングの条件入力用のテキストボックスを追加しただけです。
ビューとロジックのデータ連携はAngularの特徴であるngModelディレクティブを使った双方向バインディングにより、フレームワーク側で行ってくれます。そのため、「ビューで入力された値をロジック側で取得する」処理や「ロジック側で行った変更をビューへ反映する」といった処理を明示的に書く必要がなく、フィルタリング機能の実装に集中することができました。
今回実装を進めていく中で双方向バインディングって便利だなぁと改めて思いました。


--------------------------
システム開発のご要望・ご相談はこちらから

コメントを残す

メールアドレスが公開されることはありません。 が付いている欄は必須項目です