Angular でファイルアップローダーを実装してみた

1. Overview

前回に引き続き, Angular でのフォーム実装を学びます. 今回は, ファイルアップローダーの実装をとおして, Angular における, HTTP クラアントの実装と, 非同期処理の実装について学びます.

2. HttpClientModule / HttpClient

Angular で HTTP クライアントを実装するには, HttpClientModule / HttpClient を利用します.

src/app/app.module.ts

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

import { AppComponent } from './app.component';

@NgModule({
  declarations: [
    AppComponent
  ],
  imports: [
    BrowserModule,
    HttpClientModule
  ],
  providers: [],
  bootstrap: [AppComponent]
})
export class AppModule { }

src/app/app.component.ts

import { Component } from '@angular/core';
import { HttpClient } from '@angular/common/http';

@Component({
  selector: 'app-root',
  templateUrl: './app.component.html',
  styleUrls: ['./app.component.css']
})
export class AppComponent {
  private title = 'File Uploader by Angular';

  constructor(http: HttpClient) {
  }
}

HttpModule / Http を利用しているサンプルコードなどもありますが, それらは非推奨なので注意してください.

3. RxJS

RxJS (Reactive Extensions Library for JavaScript) とは, 非同期およびコールバックベースのコードを, 関数的, かつ, リアクティブなスタイルで作成するためのライブラリです. Angular では, 非同期処理にこの RxJS を内部的に利用しています.

3. Implement

それでは, 実際に実装をしてみます. まず, 必要となるファイルアップロードサーバーを実装する必要があります. 言語はなんでも構いません. 今回は, Go で実装してみました.

uploader.go

package main

import (
    "encoding/json"
    "io"
    "net/http"
)

func uploadHandler(w http.ResponseWriter, r *http.Request) {
    reader, err := r.MultipartReader()

    if err != nil {
        http.Error(w, err.Error(), http.StatusInternalServerError)
        return
    }

    h := w.Header()

    h.Set("Access-Control-Allow-Origin", "*")
    h.Set("Content-Type", "application/json")

    for {
        part, err := reader.NextPart()

        if err == io.EOF {
            break
        }

        if part.FileName() == "" {
            continue
        }

        res, err := json.Marshal(part)

        if err != nil {
            http.Error(w, err.Error(), http.StatusInternalServerError)
            return
        }

        w.Write(res)
    }
}

func main() {
    http.HandleFunc("/upload", uploadHandler)
    http.ListenAndServe(":8080", nil)
}

Angular の実装です. まずは, テンプレートの実装です.

src/app/app.component.html

<form>
  <input #uploader type="file" accept="image/*" (change)="upload(uploader.files)" />
<form>

#uploader はテンプレート参照変数です. change は, イベントバインディングで, ファイルダイアログでファイルが選択されたときに発火します.

次に, コンポーネントの実装です.

src/app/app.component.html

import { Component } from '@angular/core';
import { HttpClient } from '@angular/common/http';

@Component({
  selector: 'app-root',
  templateUrl: './app.component.html',
  styleUrls: ['./app.component.css']
})
export class AppComponent {
  private title = 'File Uploader by Angular';

  constructor(private http: HttpClient) {
  }

  upload(files: Array) {
    if (files.length <= 0) {
      return;
    }

    const file = files[0];
    const formData = new FormData();

    formData.append('file', file, file.name);

    this.http.post('http://localhost:8080/upload', formData)
      .subscribe(
        data => console.log(data),
        error => console.log(error)
      );
  }
}

Angular の処理が関連しているのは, HttpClient#post メソッドの部分です. HttpClient#post メソッドは, 第 1 引数にリクエスト先の URL を, 第 2 引数に POST するデータを指定します. Http#post メソッドは, RxJS の Observable を返します. Observable からデータを取得するには, Observable#subscribe メソッドを利用します. Observable#subscribe メソッドは, Observer インスタンスを引数にとります. Observer は onNext / onError / onCompleted をもっており, Observable によって呼びだされ, それぞれ, ストリームの値, エラー, 完了を通知します (上記の, サンプルでは, onCompleted は利用していませんが …).

以上で実装は完了です.

動作確認するには, まず, ファイルアップロードサーバーをバックグランドで起動しておきます.

$ go run uploader.go &

あとは, npm start を実行して, ローカルサーバーを起動します.

$ npm start

ファイルアップロードをして, ストリームの値が取得できれば成功です.

コメントを残す