Search code examples
angularangular-httpclient

Angular HttpClient Post Two Files (Multipart/form-data)


I have a Java Spring Boot controller, which accepts two MultipartFile request parameters. I've tested this endpoint via Swagger and Postman and it works. See interface below:

@RequestMapping(value = "/start/", method = RequestMethod.POST)
ResponseEntity<String> startSim(@RequestParam("scenario") MultipartFile scenarioFile, @RequestParam MultipartFile probabilityFile);

In Angular, I have added code to select/upload the files individually, which I store in my app.component.ts file as private variables named configFile and parameterFile, like so:

 uploadConfigFile(e) {
    const reader = new FileReader();
    const file = e.target.files[0];
    this.configFile = file;
    // reader.onload = () => {
    //   this.configFile = reader.result;
    // };
    // reader.readAsBinaryString(file);
  }

  uploadParameterFile(e) {
    const reader = new FileReader();
    const file = e.target.files[0];
    this.parameterFile = file;
    // reader.onload = () => {
    //   this.parameterFile = reader.result;
    // };
    // reader.readAsBinaryString(file);
  }

How can I use the post method to send both files?

  startSim(e) {
    const httpOptions = {
      headers: new HttpHeaders({
        'Content-Type': 'multipart/form-data'
      })
    };
    console.log(this.configFile);
    console.log(this.parameterFile);

    // const formData = new FormData();
    // formData.append('scenarioFile', this.configFile);
    // formData.append('probabilityFile', this.parameterFile);
    //
    // console.log(formData);

    const params = new HttpParams();
    params.append('scenarioFile', this.configFile);
    params.append('probabilityFile', this.parameterFile);

    const result = this.http.post(this.startURL, params, httpOptions);
    result.subscribe(json => console.log(json));
  }

I've tried sending the request using both FormData and HttpParams.

Update

I was able to use the form data option after I updated my rest controller to take a MultipartFile[]:

   ResponseEntity<String> startSim(@RequestParam("configList") MultipartFile[] configList);

I also got rid of the HttpOptions and let the content-type be set automatically:

// Removed

 const httpOptions = {
          headers: new HttpHeaders({
            'Content-Type': 'multipart/form-data'
          })
    };

Solution

  • You can send multiple files with these methods:

    1.) JSON.stringify

    const list = [ 
       { scenarioFile: this.configFile },
       { probabilityFile: this.parameterFile }
    ];
    
    const formData = new FormData();
    
    formData.append("configList", JSON.stringify(list));
    

    2.) or append it with the same formData key

    Reference: https://developer.mozilla.org/en-US/docs/Web/API/FormData/append

    As with regular form data, you can append multiple values with the same name

    const formData = new FormData();
    
    formData.append('configList', this.configFile);
    formData.append('configList', this.parameterFile);
    
    console.log(formData.getAll('configList'));  // Shows the content of configFile and parameterFile
    

    Then you can continue with your http post call:

    this.http
       .post(this.startURL, formData, httpOptions)
       .subscribe(json => console.log(json));