Angular 16 Express HttpClient REST API Post FormData Tutorial

Last Updated on by in Angular
Angular FormData tutorial; In this detailed post, we will discover how to use POST FormData in Angular using HttpClient, Node.js, Express, Multer and MongoDB database.FormData is an interface in JavaScript that represents a set of key/value pairs corresponding to form fields and their values.

It is commonly used to capture user input from HTML forms and send it to a server for processing.

HTTP requests are used to perform CRUD operations; similarly, the HttpClient API in Angular lets you perform the HTTP calls.

Moreover, this service is an injectable class that helps you handle HTTP requests.

Each request conjugates multiple signatures, and the return type varies based on the signature that is called the response.

To send the form data in Angular, we are going to learn specifically about the FormData object but also how to use it in an Angular application.

It’s a JavaScript object, which allows us to develop a set of key/value data structure representing form fields and their respective values.

In this step by step article, we will take the help of Angular HttpClient API to send FormData to a web server by using the Http POST method.

Angular 16 HttpClient Post FormData using Express.js REST APIs Example

  • FormData Methods
  • Set up Angular App
  • Setting up Node & Express Server
  • Build Form with Reactive Forms and Bootstrap
  • POST FormData with Angular HttpClient API

FormData Methods

You can initialize FormData object by creating an instance from new FormData interface as given below.

const formData = new FormData()

FormData Methods

Once the FormData instance is created then there are various methods available through FormData, which allows you to manage the data as per your requirement.

Methods Description
FormData.append() It includes a new value on a pre-existing key within a FormData object. If the key already exists, then the value will be added to that key without removing the first key.
FormData.delete() It deletes a key and value pair from the FormData object.
FormData.entries() FormData returns an iterator which allows looping over a set of key-value pair presenting in the object.
FormData.get() It returns the value associated with a given set of a key from the FormData object. However, if more values appended, then it will return the first value.
FormData.getAll() Returns all the values associated with a key from the FormData object.
FormData.has() It returns true if the key exists in FormData object.
FormData.keys() Returns an iterator which 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 particular key. Value is replaced if a key already exists in the FormData object.
FormData.values() Returns an iterator which allows looping over all the values existing in this object

You can check out more about the FormData object here.

Set up Angular App

Run following command to install the basic Angular app:

ng new angular-formdata-example

Run the 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.scss"
         ]

No Property Access From Index Signature

To resolve error:

Property ‘xxxName’ comes from an index signature, so it must be accessed with [‘xxxName’]

This setting makes sure profound consistency between accessing a field via the “dot” (obj.key) syntax, and “indexed” (obj["key"]) and the way which the property is declared in the type.

Without this flag, TypeScript will allow you to use the dot syntax to access fields which are not defined:

Make sure to set noPropertyAccessFromIndexSignature property to false under compilerOptions in tsconfig.json file:

"compilerOptions": {
 ...
 ...
   "strict": false,
   "noPropertyAccessFromIndexSignature": false,
 ...
 ...
}

Now, create a component where we will put all of our form data logic in an Angular app.

ng g c file-upload

Build Node Server

We will now set up a node and express server using npm packages. Along with Multer, it lets you store the image files along with other NPM packages.

Create a new “backend” folder:

mkdir backend && cd backend

Create separate package.json for node server.

npm init -y

Run command to install required NPM packages.

npm install body-parser cors express mongoose multer

Install nodemon library and get rid from restarting the server when make changes in backend files.

npm install nodemon --save-dev

Define Mongoose Schema

Create backend/models folder, also create User.js file and paste the given code.

const mongoose = require("mongoose");
const Schema = mongoose.Schema;

// Define Schema
let userSchema = new Schema(
  {
    _id: mongoose.Schema.Types.ObjectId,
    name: {
      type: String,
    },
    avatar: {
      type: String,
    },
  },
  {
    collection: "users",
  }
);

module.exports = mongoose.model("User", userSchema);

Build File Upload REST API with Multer & Express

Create new backend/public folder, here you can keep all the uploaded files.

Run the command from the backend folder’s root.

mkdir public

Create a backend/routes folder, and create router handling file by the name of user.routes.js.

const express = require("express");
const multer = require("multer");
const mongoose = require("mongoose");
const router = express.Router();

// Multer File upload settings
const DIR = "./public/";

const storage = multer.diskStorage({
  destination: (req, file, cb) => {
    cb(null, DIR);
  },
  filename: (req, file, cb) => {
    const fileName = file.originalname.toLowerCase().split(" ").join("-");
    cb(null, fileName);
  },
});

// Multer Mime Type Validation
var upload = multer({
  storage: storage,
  // limits: {
  //   fileSize: 1024 * 1024 * 5
  // },
  fileFilter: (req, file, cb) => {
    if (
      file.mimetype == "image/png" ||
      file.mimetype == "image/jpg" ||
      file.mimetype == "image/jpeg"
    ) {
      cb(null, true);
    } else {
      cb(null, false);
      return cb(new Error("Only .png, .jpg and .jpeg format allowed!"));
    }
  },
});

// User model
let User = require("../models/User");

// POST User
router.post("/create-user", upload.single("avatar"), (req, res, next) => {
  const url = req.protocol + "://" + req.get("host");
  const user = new User({
    _id: new mongoose.Types.ObjectId(),
    name: req.body.name,
    avatar: url + "/public/" + req.file.filename,
  });
  user
    .save()
    .then((result) => {
      console.log(result);
      res.status(201).json({
        message: "User registered successfully!",
        userCreated: {
          _id: result._id,
          name: result.name,
          avatar: result.avatar,
        },
      });
    })
    .catch((err) => {
      console.log(err),
        res.status(500).json({
          error: err,
        });
    });
});

// GET All Users
router.get("/", (req, res, next) => {
  User.find().then((data) => {
    res.status(200).json({
      message: "Users retrieved successfully!",
      users: data,
    });
  });
});

module.exports = router;

Configure Node/Express Server

Create index.js file inside the backend folder. And, insert the below code within the index.js file.

const express = require("express");
const mongoose = require("mongoose");
const cors = require("cors");
const bodyParser = require("body-parser");

// Routes to Handle Request
const userRoute = require("./routes/user.routes");

// Connecting MongoDB
async function mongoDbConnection() {
  await mongoose.connect(
    "mongodb://127.0.0.1:27017/test",
    {
      useNewUrlParser: true,
      useUnifiedTopology: true,
    },
    6000
  );
}
mongoDbConnection().then(() => {
  console.log("MongoDB successfully connected.");
}),
  (err) => {
    console.log("Could not connected to database : " + err);
  };

// Setup Express.js
const app = express();
app.use(bodyParser.json());
app.use(
  bodyParser.urlencoded({
    extended: false,
  })
);
app.use(cors());

// Make Images "Uploads" Folder Publicly Available
app.use("/public", express.static("public"));

// API Route
app.use("/api", userRoute);

const port = process.env.PORT || 4000;
const server = app.listen(port, () => {
  console.log("Connected to port " + port);
});

// Error
app.use((req, res, next) => {
  // Error goes via `next()` method
  setImmediate(() => {
    next(new Error("Something went wrong"));
  });
});

app.use(function (err, req, res, next) {
  console.error(err.message);
  if (!err.statusCode) err.statusCode = 500;
  res.status(err.statusCode).send(err.message);
});

Start Node Server

Setup and start the MongoDB community and MongoDB Compass GUI database in your local system.

Pass the MongoDB database URL to the mongoose.connect(‘…’) method in the backend/index.js file.

Type the command on the console then hit enter.

npx nodemon server

Next, you can checkout node server running on the following Url: http://localhost:4000/api

API Method URL
GET http://localhost:4000/api
POST /api/create-user

Build Form with Reactive Forms and Bootstrap

In this step we will create a Form for user, by using this form user can submit data and send it on the web server.

We will be using Angular’s Reactive Forms approach to get and set the data, first import the ReactiveFormsModule in the app.module.ts file.

import { ReactiveFormsModule } from '@angular/forms';

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

export class AppModule { }

Then create a form with the help of Bootstrap and Reactive Forms APIs such as FormBuilder and FormGroup.

Go to app/file-upload.component.html file and add the following code:

<div class="container mt-5">
  <h2 class="mb-5">MEAN Stack Angular HttpClient Post FormData Eample</h2>
  <form [formGroup]="form" (ngSubmit)="submitForm()">
    <div class="form-group mb-3">
      <input type="file" (change)="uploadFile($event)" />
    </div>

    <div class="form-group mb-3">
      <input
        class="form-control"
        placeholder="Image name"
        formControlName="name"
      />
    </div>

    <div class="d-grid">
      <button class="btn btn-primary btn-lg">Submit</button>
    </div>
  </form>
</div>

POST FormData with Angular HttpClient API

To make the HTTP POST request in Angular, first import the HttpClientModule API in app.module.ts file.

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

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

export class AppModule { }

Next, go to file-upload.component.ts file and add the following code inside of it.

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

@Component({
  selector: 'app-file-upload',
  templateUrl: './file-upload.component.html',
  styleUrls: ['./file-upload.component.scss'],
})
export class FileUploadComponent implements OnInit {
  form: FormGroup;

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

  ngOnInit() {}

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

  submitForm() {
    var formData: any = new FormData();
    formData.append('name', this.form.get('name').value);
    formData.append('avatar', this.form.get('avatar').value);

    this.http.post('http://localhost:4000/api/create-user', formData).subscribe(
      (response) => console.log(response),
      (error) => {
        console.log(error.message);
      }
    );
  }
}

Here, we are setting up the user entered data in the Reactive Forms form: FormGroup object (name, avatar).

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

ng serve --open

MEAN Stack Angular HttpClient Post FormData Eample

Conclusion

Multer is a middleware for handling multipart/form-data, which is typically used for uploading files in web applications. It is commonly used with Node.js and Express.js to handle file uploads.

Forms are an essential part of any web or mobile applications, and Forms allow us to gather data from the users and send that data to the webserver.

Finally, we have learned how to use Angular HttpClient API to Post FormData (multipart/form-data). I hope this tutorial helped you a lot, please consider it sharing with others.

Git Repo

Digamber - Author positronX.io

Hi, I'm Digamber Singh, a New Delhi-based full-stack developer, tech author, and open-source contributor with 10+ years' experience in HTML, CSS, JavaScript, PHP, and WordPress.