How to POST Multipart/form-data in Angular 12 with HttpClient

This tutorial walks you through on how to POST multipart FormData in Angular 12 and TypeScript 4 with HttpClient. We will upload an image file by making a POST form data request with HttpClient API using the node-based server.

If you are creating any web application so, at some point in time, you have to deal with the forms. In general, you get data provided by users and store or upload it to the remote server via app’s frontend.

Forms data can be easily managed through HTML and JavaScript. For handling the forms data, the foundation is laid the same almost for every framework, including angular as well.

FormData is a browser API which deals with the forms data. When it comes to access the form elements than this api is useful and you can make consensus with it through its various methods and properties.

The FormData interface provides a way to easily construct a set of key/value pairs representing form fields and their values, which can then be easily sent using the XMLHttpRequest.send() method. It uses the same format a form would use if the encoding type were set to “multipart/form-data”.
– MDN

Using FormData in Angular 12

The FormData API works smoothly, we create a set of key/value elements that communicate with form fields, and Angular HttpClient sends the data over to the server.

Here are the properties and methods to work with FormData:

Methods Description
FormData.append() Appends a new value onto a current key inside a FormData object or attaches the key if it does not already exist.
FormData.delete() Removes a key/value pair from a FormData object.
FormData.entries() FormData returns an iterator which supports looping over a set of key-value pair manifesting in the object.
FormData.get() It returns the value linked with a given set of a key from the FormData object. However, if more values are appended, then it will return the first value.
FormData.getAll() Returns all the values linked with a key from the FormData object.
FormData.has() It returns true if the key exists in the FormData object.
FormData.keys() Returns an iterator that allows looping over all the keys of the key-value data structure in this object.
FormData.set() It is used to set the value into the FormData object with the specific key. Value is reinstated if a key already exists in the FormData object.
FormData.values() Returns an iterator allowing to go through all values included in this object.

It would be best if you had a server working on http://localhost:8000 with /file-upload endpoint; it must work with POST request for storing or uploading files on the server.

Run following command to install the basic Angular app:

ng new angular-formdata-example

# ? Would you like to add Angular routing? Yes
# ? Which stylesheet format would you like to use? CSS

Execute command to install the Bootstrap.

npm install bootstrap

Go to angular.json file and inject the bootstrap style sheet inside the styles array like given below.

"styles": [
          "node_modules/bootstrap/dist/css/bootstrap.min.css",
          "src/styles.css"
         ]

Now, your Angular app is ready to be started via following command.

ng serve --open

Next, generate a component for file uploading in angular.

ng generate component upload-file

Add the code in app/upload-file.component.html file to create the file uploading layout:

<form [formGroup]="form" (ngSubmit)="submit()">
    <div class="form-group">
        <input type="file" (change)="upload($event)">
    </div>
    <div class="form-group">
        <button class="btn btn-danger">Upload</button>
    </div>
</form>

POST Multipart/FormData to Upload File

Register and import the HttpClientModule API in app.module.ts:

Configures the dependency injector for HttpClient with supporting services for XSRF. Automatically imported by HttpClientModule.

import { HttpClientModule } from '@angular/common/http';

@NgModule({
  declarations: [...],
  imports: [
     HttpClientModule
  ],
  bootstrap: [...]
})

export class AppModule { }

Open app/upload-file.component.ts file and import required packages:

import { FormBuilder, FormGroup } from "@angular/forms";
import { HttpClient } from '@angular/common/http';

Declare the file upload URL and other configs.

export class UploadFileComponent implements OnInit {
  form: FormGroup;
  API: http://localhost:8000/file-upload;

Inject HttpClient and FormBuilder services in the constructor, also initiate the form group.

constructor(
    public fb: FormBuilder,
    private http: HttpClient
  ) {
    this.form = this.fb.group({
      img: [null]
    })
  }

Create an upload() method; this function is triggered when the user chooses the file.

upload(event) {
    const file = (event.target as HTMLInputElement).files[0];
    this.form.patchValue({
      img: file
    });
    this.form.get('img').updateValueAndValidity()
 }

The submit() function will be used to POST FormData or multipart/form-data to the server.

submit() {
    var formData: any = new FormData();
    formData.append("img", this.form.get('img').value);

    this.http.post(this.API, formData).subscribe(
      (response) => console.log(response),
      (error) => console.log(error)
    )
 }

Eventually, we have placed everything at its place, for the reference here is the final code.

import { Component, OnInit } from '@angular/core';
import { FormBuilder, FormGroup } from "@angular/forms";
import { HttpClient } from '@angular/common/http';


@Component({
  selector: 'app-upload-file',
  templateUrl: './upload-file.component.html',
  styleUrls: ['./upload-file.component.css']
})

export class UploadFileComponent implements OnInit {
  form: FormGroup;
  API: http://localhost:8000/file-upload;

  constructor(
    public fb: FormBuilder,
    private http: HttpClient
  ) {
    this.form = this.fb.group({
      img: [null]
    })
  }

  ngOnInit() { }

  upload(event) {
    const file = (event.target as HTMLInputElement).files[0];
    this.form.patchValue({
      img: file
    });
    this.form.get('img').updateValueAndValidity()
  }

  submit() {
    var formData: any = new FormData();
    formData.append("img", this.form.get('img').value);

    this.http.post(this.API, formData).subscribe(
      (response) => console.log(response),
      (error) => console.log(error)
    )
  }

}