Angular - POST uploaded file
Look at my code, but be aware. I use async/await, because latest Chrome beta can read any es6 code, which gets by TypeScript with compilation. So, you must replace asyns/await by .then()
.
Input change handler:
/** * @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;}
Submit handler:
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. That service also stored uploading progress in progress$ property, and in other places, you can subscribe on it and get new value every 500ms.
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);}}
Looking onto this issue Github - Request/Upload progress handling via @angular/http, angular2 http does not support file upload yet.
For very basic file upload I created such service function as a workaround (using Тимофей'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); });}
your http service file:
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; }}
call your function (Component file):
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); });}
your html code:
<input type="file" class="form-control" name="documents" (change)="onChange($event)" [(ngModel)]="stock.documents" #documents="ngModel">