AngularFireがStorageにも対応してたので使ってみた

以前、[AngularでCloud Storage for Firebaseにファイルアップロード](https://qiita.com/daikiojm/items/1c5940d618b3b644439a)という記事でPure JavaScriptのSDKを使いAngularからFirebase Cloud Storageを使ってみましたが、AngularFireにもStorageを扱う機能が追加されたようなので、そちらを使ってみたいと思います。(5.0.0-rc.6で使えるみたい)

公式ドキュメント: [AngularFireStorage](https://github.com/angular/angularfire2/blob/master/docs/storage/storage.md)

# 前提

* **[AngularでCloud Storage for Firebaseにファイルアップロード](https://qiita.com/daikiojm/items/1c5940d618b3b644439a)の「Firebaseの設定」までが完了済み**
* AngularCLI v1.7.4で`ng new`したプロジェクト

# サンプル実装

AngularFireのインストールと、新しく追加されたAPIを使うところから始めていきます。

## AngularFireのインストールとセットアップ

今回は[angularfire2](https://github.com/angular/angularfire2)の方を使います。
※ firebaseも必要なので、同時にインストールします。

```
$ npm install firebase angularfire2 --save
```

今回(2018/05/04現在)インストールされたバージョンは以下のとおりです。

* angularfire2@5.0.0-rc.6.0
* firebase@4.13.1


`src/environments/environment.ts`を開き、「Firebaseの設定」で取得した設定情報を次のように設定しておきます。

```ts:environment.ts
export const environment = {
  production: false,
  firebase: {
    apiKey: '<your-key>',
    authDomain: '<your-project-authdomain>',
    databaseURL: '<your-database-URL>',
    projectId: '<your-project-id>',
    messagingSenderId: '<your-messaging-sender-id>'
  }
};
```

次に、`src/app/app.module.ts`を開き、次のコメントに示した箇所を変更します。

```ts:src/app/app.module.ts
import { BrowserModule } from '@angular/platform-browser';
import { NgModule } from '@angular/core';
import { AngularFireModule } from 'angularfire2'; // 追加でインポート
import { AngularFireStorageModule } from 'angularfire2/storage'; // 追加でインポート

import { AppComponent } from './app.component';
import { FileUploadComponent } from './file-upload/file-upload.component'; // 今回追加したファイルアップロードをするコンポーネント
import { environment } from '../environments/environment'; // environmentをインポートしておく

@NgModule({
  declarations: [
    AppComponent,
    FileUploadComponent
  ],
  imports: [
    BrowserModule,
    AngularFireModule.initializeApp(environment.firebase), // importsに追加
    AngularFireStorageModule,
  ],
  providers: [],
  bootstrap: [AppComponent]
})
export class AppModule {}
```

## ファイルアップロードの実装

使用するコンポーネントにインポートして、コンストラクタにセットしておきます。

```ts:file-upload.component.ts
import { Component, OnInit } from '@angular/core';
import { AngularFireStorage } from 'angularfire2/storage';
...

  constructor(private storage: AngularFireStorage) {}

...
```

コンポーネントのHTMLテンプレート側です。

`input`のchangeイベントにonChangeInput()メソッドをバインドして、ファイル選択がされた際は、即時アップロード処理が呼ばれるようにしています。

```html:file-upload.component.html
<h1>ファイルアップロード🐶</h1>

<!-- テキストファイルを選択するinput -->
<div id="input-area">
  <input type="file" accept="image/*" (change)="onChangeInput($event)">
</div>

<!-- アップロードしたファイルを表示するエリア -->
<img [src]="uploadResult?.downloadURL || ''">
```

次に、コンポーネントのクラス側です。

```ts:file-upload.component.ts
import { Component } from '@angular/core';
import { Observable } from 'rxjs/Observable';
import { AngularFireStorage } from 'angularfire2/storage';

@Component({
  selector: 'app-file-upload',
  templateUrl: './file-upload.component.html',
  styleUrls: ['./file-upload.component.css']
})
export class FileUploadComponent {
  // ファイルのURL
  public uploadFileUrl$: Observable<string>;

  constructor(private storage: AngularFireStorage) {}

  onChangeInput(evt) {
    const file: File = evt.target.files[0];

    // ファイル名を取得
    const fileName = file.name;

    // 保存先,ファイル名を指定
    const filePath = 'upload_files/' + fileName;

    // uploadメソッドでファイルをアップロード
    const task = this.storage.upload(filePath, file);

    // アップロード完了後にダウンロードURLを取得
    this.uploadFileUrl$ = task.downloadURL();
  }
}
```

ダウンロードURLをObservableで受け取れるのはかなり便利ですね。

# その他

それにしても、AngularFireはいつまでRCなのか...