Actually, I'm working on a Spring REST API with an interface coded in Angular 2.
My problem is I can't upload a file with Angular 2.
My Webresources in java is that :
@RequestMapping(method = RequestMethod.POST, value = "/upload") public String handleFileUpload(@RequestParam MultipartFile file) { //Dosomething }
And it is perfectly working when I call it through URL request with Auth header etc ... ( with Advanced Rest Client extension for Chrome )
Proof: (everything works fine in that case )
I added the
<bean id="multipartResolver" class="org.springframework.web.multipart.commons.CommonsMultipartResolver" />
Spring config file and the Pom dependency
<dependency> <groupId>commons-fileupload</groupId> <artifactId>commons-fileupload</artifactId> <version>1.2</version> </dependency>
BUT when I try to do the same thing with a webform :
<input type="file" #files (change)="change(files)"/> <pre>{{fileContents$|async}}</pre>
With the (change) method :
change(file) { let formData = new FormData(); formData.append("file", file); console.log(formData); let headers = new Headers({ 'Authorization': 'Bearer ' + this.token, 'Content-Type': 'multipart/form-data' }); this.http.post(this.url, formData, {headers}).map(res => res.json()).subscribe((data) => console.log(data)); /* Observable.fromPromise(fetch(this.url, {method: 'post', body: formData}, {headers: this.headers} )).subscribe(()=>console.log('done')); */ }
My web service returns me an error 500, with that in tomcat logs: http://pastebin.com/PGdcFUQb
I tried the 'Content-Type': undefined
method too but without success ( the web service return me a 415 error in that case.
Can someone help me to figure out what's the problem is?
Problem solved, I'll update that question later with my code :) but, have a look on the plunker it's working perfectly well. Thanks.
This is actually really easy to do in the final release. Took me a while to wrap my head around it because most information about it that I've come across is outdated. Posting my solution here in case anyone else is struggling with this.
import { Component, ElementRef, Input, ViewChild } from '@angular/core'; import { Http } from '@angular/http'; @Component({ selector: 'file-upload', template: '<input type="file" [multiple]="multiple" #fileInput>' }) export class FileUploadComponent { @Input() multiple: boolean = false; @ViewChild('fileInput') inputEl: ElementRef; constructor(private http: Http) {} upload() { let inputEl: HTMLInputElement = this.inputEl.nativeElement; let fileCount: number = inputEl.files.length; let formData = new FormData(); if (fileCount > 0) { // a file was selected for (let i = 0; i < fileCount; i++) { formData.append('file[]', inputEl.files.item(i)); } this.http .post('http://your.upload.url', formData) // do whatever you do... // subscribe to observable to listen for response } } }
Then just use it like so:
<file-upload #fu (change)="fu.upload()" [multiple]="true"></file-upload>
That is really all there is to it.
Alternatively, capture the event object and get the files from the srcElement. Not sure if any way is better than the other, to be honest!
Keep in mind FormData is IE10+, so if you have to support IE9 you'll need a polyfill.
Update 2017-01-07
Updated code to be able to handle uploading of multiple files. Also my original answer was missing a rather crucial bit concerning FormData (since I moved the actual upload logic to a separate service in my own app I was handling it there).
In fact, at the moment, you can only provide string input for post
, put
and patch
methods of the Angular2 HTTP support.
To support that, you need to leverage the XHR object directly, as described below:
import {Injectable} from 'angular2/core'; import {Observable} from 'rxjs/Rx'; @Injectable() export class UploadService { constructor () { this.progress$ = Observable.create(observer => { this.progressObserver = observer }).share(); } private makeFileRequest (url: string, params: string[], files: File[]): Observable { return Observable.create(observer => { 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) { observer.next(JSON.parse(xhr.response)); observer.complete(); } else { observer.error(xhr.response); } } }; 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); }); } }
See this plunkr for more details: https://plnkr.co/edit/ozZqbxIorjQW15BrDFrg?p=info.
There is a an issue and a pending PR regarding this in the Angular repo:
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With