Angular Materialでファイル選択ボタン


小ネタです。
Angular Materialを使ったプロジェクトで、ファイル選択input <input type="file" /> を使うときにボタンをmat-buttonにする方法を紹介します。

HTML

<input type="file" style="display: none" #fileInput accept="image/*" (change)="onChangeFileInput()" />
<button mat-raised-button color="primary" class="file-select-button" (click)="onClickFileInputButton()">
 <mat-icon>attach_file</mat-icon>
  ファイルを選択
</button>

<p class="file-name" *ngIf="!file; else fileName">ファイルが選択されていません</p>
<ng-template #fileName>
  <p class="file-name">{{ file?.name }}</p>
</ng-template>
  • 1行目: 通常のinputコントロールに対して #fileInput という形でテンプレートリファレンスを追加。 また、このコントロールはmat-buttonに置き換える予定なので、 display: none で非表示にする
  • 2-4行目: inputの代わりになるmat-button、 クリックした際に発火するイベントハンドラを設定
  • 7行目以降: 選択したファイル名の表示

TypeScript

import { Component, ViewChild } from '@angular/core';  // ViewChildをimport
// ... 中略 ...
export class FileInputComponent  {
  @ViewChild('fileInput')
  fileInput;

  file: File | null = null;

  onClickFileInputButton(): void {
    this.fileInput.nativeElement.click();
  }

  onChangeFileInput(): void {
    const files: { [key: string]: File } = this.fileInput.nativeElement.files;
    this.file = files[0];
  }
}
  • 1行目: テンプレートリファレンスを使って、コンポーネントのクラス側からinputにアクセスするために ViewChild をimportしておく
  • 4行目: テンプレートリファレンスを使ってinput要素を取得しておく
  • 9行目: mat-buttonが押さたイベントをinput要素に伝える処理
  • 13行目以降: inputのchangeイベントの発火を受けて、file変数にファイル内容を格納する処理

サンプル

stackblitzにサンプルを用意しました。
https://stackblitz.com/edit/angular-material-file-select