Juicy Juicy - 3 months ago 21
TypeScript Question

Getting the server response after xhr.send() in an Observable

I implemented a method to POST a file in my Angular 2 app. It is based on the solution I found here.

Because Angular 2 doesn't support file uploads by itself, the solution has to leverage

xhr
. This is what the working solution looks like:

The component method:

onSubmit(): void {
this.inputModuleService.postFile(this.files).subscribe(() => {
console.log('sent');
});
}


The service method:

postFile (files: File[]): Observable<string> {
var url = this.uploadURL;

return Observable.create(observer => {
var formData: FormData = new FormData()
var xhr: XMLHttpRequest = new XMLHttpRequest();

formData.append("upload", 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.open('POST', url, true);
xhr.send(formData);
});
}


My issue is that I don't understand how to get the response back to the
onSubmit()
method after the call to
xhr.send()
. Angular2 and the concept of observables and promises are all new to me.

How can I get the server's response from this observable?

Answer

The server response is provided to the success and error callbacks of subscribe():

onSubmit(): void {
    this.inputModuleService.postFile(this.files).subscribe(
      response => {
          //response is the server's response, parsed into a javascript object
          console.log('server responded: ', response);
      },
      error => {
          //server response emitted when xhr.status !== 200
          console.error(error);
      }
   );
}

This line:

formData.append("upload", files[i], files[i].name);

Will throw errors because i is undefined. The code you copied from had that line within a loop and i was the current index. That's not the case in your code.

Your function declaration:

postFile (files: File[]): Observable<string>

Should be changed to

postFile (files: File[]): Observable<any>

Because the Observable returned by postFile emits objects, not strings.

If you mean to upload just one file, you should also change files: File[] to file: File and append the file with:

formData.append("upload", file, file.name);