Upload image with HttpClient

37,330

Solution 1

For me the trick was not to set the content-type to multipart/form-data. But that was done automatically for me.

<label>
  <input type="file" (change)="setFiles($event)" style="display:none" multiple/>
  <a mat-raised-button color="primary">
    <mat-icon>file_upload</mat-icon>
    Select Documents
  </a>
</label>

Here's my code that uploads multipart/form-data. No need to set the headers.

private setFile(event) {
    let files = event.srcElement.files
    if (!files) {
      return
    }

    let path = `${environment.celoApiEndpoint}/api/patientFiles`
    let data = {"patientData": {
      "uid": "",
      "firstName": "",
      "lastName": "",
      "gender": "Not Specified",
      "dateOfBirth": ""
    }}
    // let headers = new HttpHeaders()
    //   .set('content-type', 'multipart/form-data; boundary=----WebKitFormBoundary7MA4YWxkTrZu0gW')
    // let headers = new HttpHeaders().set('content-type', 'multipart/form-data')
    const formData: FormData = new FormData();

    for (let i = 0; i < files.length; i++) {
      formData.append(i.toString(), files[i], files[i].name);
    }
    formData.append("data", JSON.stringify(data));
    this.http.post(path, formData).subscribe(
      (r)=>{console.log('got r', r)}
    )
  }

Solution 2

I don't think the issue is with angular, I used the same code to send a file to the server (I am using spring in backend), the only difference is I am not observing the request or converting the response to promise.

See my code below:

let formData: FormData = new FormData();
formData.append('file', this.fileToUpload);

this.http.put(this.usersUrl, formData).subscribe(
    data => {
        console.log(data); 
    },
    error => {
        console.log(error);
    }
);
Share:
37,330
mrkvon
Author by

mrkvon

Updated on June 21, 2020

Comments

  • mrkvon
    mrkvon almost 4 years

    Problem

    I try to upload an image with angular's HttpClient to API Content-Type: multipart/form-data (angular v4+). Is it supported? How to do it?

    The upload works with XMLHttpRequest when using module like ng2-fancy-image-uploader. I would prefer to use a custom method with HttpClient which i could put into a http service together with other methods for accessing API.

    Here is what i have tried so far:

    model.service.ts

    import { Injectable } from '@angular/core';
    import { HttpClient, HttpHeaders, HttpResponse } from '@angular/common/http';
    import 'rxjs/add/operator/toPromise';
    
    @Injectable()
    export class ModelService {
      constructor(private http: HttpClient) { }
    
      public async updateAvatar(file: File): Promise<void> {
    
        // headers
        const headers = new HttpHeaders()
          .append('Content-Type', 'multipart/form-data');
    
        const formData: FormData = new FormData();
        formData.append('avatar', file, file.name);
    
        const response: HttpResponse = await this.http
          .patch('https://example.com/avatar', formData, { headers, observe: 'response' })
          .toPromise();
    
        console.log(response.status);
      }
    }
    

    avatar-uploader.component.ts

    import { Component, ElementRef, OnInit, ViewChild } from '@angular/core';
    import { ModelService } from './path/to/model.service';
    
    @Component({
      selector: 'app-avatar-uploader',
      template: '<input type="file" #fileInput (changes)="uploadAvatar()">'
    })
    export class AvatarUploaderComponent implements OnInit {
    
      @ViewChild('fileInput') fileInputElement: ElementRef;
    
      constructor() { }
    
      ngOnInit() { }
    
      public async uploadAvatar() {
        const file: File = this.fileInputElement.nativeElement.files[0];
    
        await this.model.updateAvatar(file);
      }
    
    }
    

    This version sends a request to (express) API, but multer (a library for parsing multipart/form-data requests) fails to parse the request.

    So i guess i either use the HttpClient incorrectly, or it doesn't support multipart/form-data requests.

    I guess one could send base64 encoded file or use XmlHttpRequest, but i ask specifically about HttpClient's ability to do it.