2015-09-06 5 views
49

私はAngular,TypeScriptを使用してファイルをJSONデータとともにサーバーに送信しています。Angular - POSTアップロードファイル

以下

は私のコードです:

import {Component, View, NgFor, FORM_DIRECTIVES, FormBuilder, ControlGroup} from 'angular2/angular2'; 
import {Http, Response, Headers} from 'http/http'; 


@Component({ selector: 'file-upload' }) 
@View({ 
directives: [FORM_DIRECTIVES], 
template: ` 
<h3>File Upload</h3> 

<div> 
    Select file: 
    <input type="file" (change)="changeListener($event)"> 
</div> 

` 
}) 
export class FileUploadCmp { 

public file: File; 
public url: string; 
headers: Headers; 


constructor(public http: Http) { 
    console.log('file upload Initialized'); 
    //set the header as multipart   
    this.headers = new Headers(); 
    this.headers.set('Content-Type', 'multipart/form-data'); 
    this.url = 'http://localhost:8080/test'; 
} 

//onChange file listener 
changeListener($event): void { 
    this.postFile($event.target); 
} 

//send post file to server 
postFile(inputValue: any): void { 

    var formData = new FormData(); 
    formData.append("name", "Name"); 
    formData.append("file", inputValue.files[0]); 

    this.http.post(this.url +, 
     formData , 
     { 
      headers: this.headers 

     }); 
} 

} 

は、どのように私はStringにformDataを変換し、それをサーバーに送信することができますか? AngularJS(v1)で覚えていますが、transformRequestを使用します。

var data : { 
    name: string; 
    file: File; 
} = { 
    name: "Name", 
    file: inputValue.files[0] 
    }; 

は、その後、あなたがJSON.stringifyでサーバーに送信(データ):いるFormDataクラスも現時点ではサポートされていないため

+0

は、データがthis.http.postラインの前に変換することができないのですか? httpは観測可能であり、オプションを取ります。ソースを検索しようとします(例:https:// github)。com/angular/angular/blob/8ed22ce6e7ce0e00c12b036d02627424c6b4ff35/modules/angular2/src/http/http.ts –

+0

これについて進歩はありましたか? – Canastro

+0

GitHubに関する保留中の機能リクエストがあります。https://github.com/angular/angular/issues/2803 – martin

答えて

40

は私のコードを見て、しかし、注意してください。私はasync/awaitを使用しています。最新のChromeベータ版では、コンパイル時にTypeScriptによって取得されるes6コードを読み取ることができるためです。したがって、asyns/awaitを.then()に置き換える必要があります。

入力変更ハンドラは:

public async psdTemplateUploadHandler(): Promise<any> { 
    let result: any; 

    if (!this.psdTemplates.length) { 
     return; 
    } 

    this.isSubmitted = true; 

    this.fileUploadService.getObserver() 
     .subscribe(progress => { 
      this.uploadProgress = progress; 
     }); 

    try { 
     result = await this.fileUploadService.upload(this.uploadRoute, this.psdTemplates); 
    } catch (error) { 
     document.write(error) 
    } 

    if (!result['images']) { 
     return; 
    } 

    this.saveUploadedTemplatesData(result['images']); 
    this.redirectService.redirect(this.redirectRoute); 
} 

FileUploadService:

/** 
* @param fileInput 
*/ 
public psdTemplateSelectionHandler (fileInput: any){ 
    let FileList: FileList = fileInput.target.files; 

    for (let i = 0, length = FileList.length; i < length; i++) { 
     this.psdTemplates.push(FileList.item(i)); 
    } 

    this.progressBarVisibility = true; 
} 

ハンドラを提出してください。このサービスでは、アップロードの進行状況が$ propertyに保存されていましたが、他の場所では、500msごとに新しい値を取得できます。この問題Github - Request/Upload progress handling via @angular/httpに探し

import { Component } from 'angular2/core'; 
import { Injectable } from 'angular2/core'; 
import { Observable } from 'rxjs/Observable'; 
import 'rxjs/add/operator/share'; 

@Injectable() 
export class FileUploadService { 
/** 
* @param Observable<number> 
*/ 
private progress$: Observable<number>; 

/** 
* @type {number} 
*/ 
private progress: number = 0; 

private progressObserver: any; 

constructor() { 
    this.progress$ = new Observable(observer => { 
     this.progressObserver = observer 
    }); 
} 

/** 
* @returns {Observable<number>} 
*/ 
public getObserver(): Observable<number> { 
    return this.progress$; 
} 

/** 
* Upload files through XMLHttpRequest 
* 
* @param url 
* @param files 
* @returns {Promise<T>} 
*/ 
public upload (url: string, files: File[]): Promise<any> { 
    return new Promise((resolve, reject) => { 
     let formData: FormData = new FormData(), 
      xhr: XMLHttpRequest = new XMLHttpRequest(); 

     for (let i = 0; i < files.length; i++) { 
      formData.append("uploads[]", files[i], files[i].name); 
     } 

     xhr.onreadystatechange =() => { 
      if (xhr.readyState === 4) { 
       if (xhr.status === 200) { 
        resolve(JSON.parse(xhr.response)); 
       } else { 
        reject(xhr.response); 
       } 
      } 
     }; 

     FileUploadService.setUploadUpdateInterval(500); 

     xhr.upload.onprogress = (event) => { 
      this.progress = Math.round(event.loaded/event.total * 100); 

      this.progressObserver.next(this.progress); 
     }; 

     xhr.open('POST', url, true); 
     xhr.send(formData); 
    }); 
} 

/** 
* Set interval for frequency with which Observable inside Promise will share data with subscribers. 
* 
* @param interval 
*/ 
private static setUploadUpdateInterval (interval: number): void { 
    setInterval(() => {}, interval); 
} 
} 
+0

xhr.setRequestHeader( 'X-Requested- '、' XMLHttpRequest '); 'それが働くために – patad

+0

@patad:あなたはそれに問題がありますか? xmlファイルをアップロードすると、自動的に '------ WebKitFormBoundaryklb8qUzyCQJSI440が追加されます。 コンテンツの処理:フォームデータ。私のファイルの中で "name =" file "'。送信中に余分なデータをファイルに追加したくない場合は、その方法を知っていますか?また、jpgのような画像をアップロードすると、アップロードした後はもはやjpgファイルではなくなりました。だから私の質問は:送信中に元のファイルを保持する方法ですか? –

+1

なぜ 'setInterval()'が必要なのですか? – jrub

2

まず、あなたは、あなた自身のインラインTS-クラスを作成する必要があります

let opts: RequestOptions = new RequestOptions(); 
opts.method = RequestMethods.Post; 
opts.headers = headers; 
this.http.post(url,JSON.stringify(data),opts); 
+0

https://developer.mozilla.org/en-US/docs/Web/API/FormData#Browser_compatibility サポートは実際にそれほど悪くはありません。アップロードされたファイルがバイナリやそのようなものである場合、JSON.stringifyにいくつかの問題があると思います。 – csga5000

4

私のプロジェクトでは、XMLHttpRequestを使用してmultipart/form-dataを送信します。 私はそれがあなたに合うと思います。ここで

uploaderコード

let xhr = new XMLHttpRequest(); 
xhr.open('POST', 'http://www.example.com/rest/api', true); 
xhr.withCredentials = true; 
xhr.send(formData); 

は一例です:https://github.com/wangzilong/angular2-multipartForm

+1

あなた自身のライブラリ(またはユーティリティ)にリンクするだけでよい答えはありません。それにリンクして、なぜそれが問題を解決するのかを説明し、それを使ってコードを提供し、より良い答えを出すことを断言する。参照:[私はコミュニティにやさしい方法で外部リソースにリンクするにはどうすればいいですか?](// meta.stackexchange.com/questions/94022/) – Tunaki

23

、angular2のhttpまだファイルのアップロードをサポートしていません。私は(Тимофей's answerを使用して)回避策として、このようなサービス機能を作成し、非常に基本的なファイルアップロードのために

uploadFile(file:File):Promise<MyEntity> { 
    return new Promise((resolve, reject) => { 

     let xhr:XMLHttpRequest = new XMLHttpRequest(); 
     xhr.onreadystatechange =() => { 
      if (xhr.readyState === 4) { 
       if (xhr.status === 200) { 
        resolve(<MyEntity>JSON.parse(xhr.response)); 
       } else { 
        reject(xhr.response); 
       } 
      } 
     }; 

     xhr.open('POST', this.getServiceUrl(), true); 

     let formData = new FormData(); 
     formData.append("file", file, file.name); 
     xhr.send(formData); 
    }); 
} 
+1

素晴らしい!しかし、私は 'xhr.setRequestHeader( 'X-Requested-With'、 'XMLHttpRequest');'を追加する必要がありました。 – patad

+2

ありがとう! xhr.openの行が私のために働いた後にこれを追加する必要がある場合は: 'xhr.setRequestHeader( 'Authorization'、 'Bearer' + __your_auth_key __); ' – Steve

+0

これは今サポートされていますか? –

8

あなたのHTTPサービスのファイル:

import { Injectable } from "@angular/core"; 
import { ActivatedRoute, Router } from '@angular/router'; 
import { Http, Headers, Response, Request, RequestMethod, URLSearchParams, RequestOptions } from "@angular/http"; 
import {Observable} from 'rxjs/Rx'; 
import { Constants } from './constants'; 
declare var $: any; 

@Injectable() 
export class HttpClient { 
    requestUrl: string; 
    responseData: any; 
    handleError: any; 

    constructor(private router: Router, 
    private http: Http, 
    private constants: Constants, 
) { 
    this.http = http; 
    } 

    postWithFile (url: string, postData: any, files: File[]) { 

    let headers = new Headers(); 
    let formData:FormData = new FormData(); 
    formData.append('files', files[0], files[0].name); 
    // For multiple files 
    // for (let i = 0; i < files.length; i++) { 
    //  formData.append(`files[]`, files[i], files[i].name); 
    // } 

    if(postData !=="" && postData !== undefined && postData !==null){ 
     for (var property in postData) { 
      if (postData.hasOwnProperty(property)) { 
       formData.append(property, postData[property]); 
      } 
     } 
    } 
    var returnReponse = new Promise((resolve, reject) => { 
     this.http.post(this.constants.root_dir + url, formData, { 
     headers: headers 
     }).subscribe(
      res => { 
      this.responseData = res.json(); 
      resolve(this.responseData); 
      }, 
      error => { 
      this.router.navigate(['/login']); 
      reject(error); 
      } 
    ); 
    }); 
    return returnReponse; 
    } 
} 

は(コンポーネント・ファイルを、あなたの関数を呼び出します):

onChange(event) { 
    let file = event.srcElement.files; 
    let postData = {field1:"field1", field2:"field2"}; // Put your form data variable. This is only example. 
    this._service.postWithFile(this.baseUrl + "add-update",postData,file).then(result => { 
     console.log(result); 
    }); 
} 

HTMLコード:

<input type="file" class="form-control" name="documents" (change)="onChange($event)" [(ngModel)]="stock.documents" #documents="ngModel"> 
+0

実際に使用されている唯一の回答の1つ – csga5000

+0

「エラーTS2339:プロパティ 'ファイル'」がタイプ 'Element'に存在しません。 'thanks –

+0

'onChange(){...}'は 'onChange (イベント){...} 'はエラーを修正します:プロパティファイルは存在しません;) –

関連する問題