Angular File Upload: Angular Image Upload Example

In this example, we will use Node.js as a backend server. So first, we install Angular using Angular CLI and then start working on this Angular file upload demo.

Angular file upload

To upload files in Angular, use the ng2-file-upload library. For managing the uploaded files at the backend, we use the multer library. Multer is a node.js middleware for handling multipart/form-data, primarily used for uploading files. It is written on top of the busboy for maximum efficiency. Therefore, Multer will not process any form which is not multipart.

To upload from scratch, follow the below steps. But, first, we start this project by installing Angular on our machine.

Step 1: Install Angular.

If you have not installed Angular CLI globally on your machine, install it using the following command. We are using NPM as a package manager for JS development.

Today NPM is the biggest repository for any programming language, and it has almost every package you need in a web or mobile development project. npm means the node package manager. If you have previous work with any front-end development stuff, this package manager is familiar.

In January 2020, over 700,000 packages were reported to be listed in the npm registry, making it the most significant single language code repository on the planet.

npm install -g @angular/cli

# or

yarn add global @angular/cli

Now, create a local project using the following command.

ng new fileupload

Now, start the application using the following command.

ng serve --open

Step 2: Install the rxjs-compat library.

Since third-party libraries do not support the RxJS, one change in Angular now depends on the latest TypeScript and RxJS versions. So, if you install third-party packages right now, it is not compatible with Angular.

In the future, all third-party libraries might upgrade their packages, but it is not compatible with Angular.

So, to fill the gap between Angular and third-party packages, we need to install the following library. That is it.

npm install rxjs-compat --save

Step 3: Install Bootstrap 4.

Go to your terminal and type the following command.

npm install bootstrap --save

After that, go to the inside src folder, open the styles.css file, and import the bootstrap.min.css file.

@import "~bootstrap/dist/css/bootstrap.min.css"

Step 4: Install the ng-file-upload library.

Type the following command to install the library.

npm install ng2-file-upload --save

Now, write the following code inside an app.module.ts file.

// app.module.ts

import { BrowserModule } from '@angular/platform-browser';
import { NgModule } from '@angular/core';
import { FileSelectDirective } from 'ng2-file-upload';
import { FormsModule } from '@angular/forms';
import { AppComponent } from './app.component';

@NgModule({
  declarations: [
    AppComponent,
    FileSelectDirective
  ],
  imports: [
    BrowserModule,
    FormsModule
  ],
  providers: [],
  bootstrap: [AppComponent]
})
export class AppModule { }

We are using Angular Forms, the package included in Angular by default project.

Okay, so we have imported FormsModule and FileSelectDirective.

Now, write the following code inside an app.component.ts file.

// app.component.ts

import { Component, OnInit } from '@angular/core';
import {  FileUploader, FileSelectDirective } from 'ng2-file-upload/ng2-file-upload';

const URL = 'http://localhost:3000/api/upload';

@Component({
  selector: 'app-root',
  templateUrl: './app.component.html',
  styleUrls: ['./app.component.css']
})
export class AppComponent implements OnInit {
  title = 'app';

  public uploader: FileUploader = new FileUploader({url: URL, itemAlias: 'photo'});

  ngOnInit() {
    this.uploader.onAfterAddingFile = (file) => { file.withCredentials = false; };
    this.uploader.onCompleteItem = (item: any, response: any, status: any, headers: any) => {
         console.log('ImageUpload:uploaded:', item, status, response);
         alert('File uploaded successfully');
     };
 }
}

Finally, write the following code inside an app.component.html file.

<input type="file" name="photo" ng2FileSelect [uploader]="uploader" />

<button type="button" class="btn btn-success btn-s" 
  (click)="uploader.uploadAll()" 
  [disabled]="!uploader.getNotUploadedItems().length" >
      Upload an Image
</button>

 

Angular 6 File Upload Tutorial

Step 5: Create Node.js backend.

First, install the following node modules.

npm install express multer body-parser --save

We have installed Express as a web framework for Node.js development.

Install nodemon as a dev dependency.

npm install nodemon --save-dev

Create a new directory inside root called uploads.

Okay, now create one file in the project root folder called server.js.

// server.js

const path = require('path');
const fs = require('fs');
const express = require('express');
const multer = require('multer');
const bodyParser = require('body-parser')
const app = express();
const router = express.Router();

const DIR = './uploads';
 
let storage = multer.diskStorage({
    destination: (req, file, cb) => {
      cb(null, DIR);
    },
    filename: (req, file, cb) => {
      cb(null, file.fieldname + '-' + Date.now() + '.' + path.extname(file.originalname));
    }
});
let upload = multer({storage: storage});

app.use(bodyParser.json());
app.use(bodyParser.urlencoded({extended: true}));
 
app.use(function (req, res, next) {
  res.setHeader('Access-Control-Allow-Origin', 'http://localhost:4200');
  res.setHeader('Access-Control-Allow-Methods', 'POST');
  res.setHeader('Access-Control-Allow-Headers', 'X-Requested-With,content-type');
  res.setHeader('Access-Control-Allow-Credentials', true);
  next();
});
 
app.get('/api', function (req, res) {
  res.end('file catcher example');
});
 
app.post('/api/upload',upload.single('photo'), function (req, res) {
    if (!req.file) {
        console.log("No file received");
        return res.send({
          success: false
        });
    
      } else {
        console.log('file received');
        return res.send({
          success: true
        })
      }
});
 
const PORT = process.env.PORT || 3000;
 
app.listen(PORT, function () {
  console.log('Node.js server is running on port ' + PORT);
});

In the above code, we have defined the express router. Routing refers to how an application’s endpoints (URIs) respond to client requests.

The Express Router class helps in the creation of route handlers. 

Express apps utilize routers that are necessarily containers for a set of middleware. We can put this middleware holder only on a specific route, which allows us to keep our logic in separate files and bring them together on our terms.

So, I have used a multer module to store the file.

Multer adds the body object and the file or files object to a request object. The body object contains the values of text fields of a form; a file or files object contains the files uploaded via the HTML form. Don’t forget the enctype=”multipart/form-data” in your HTML form.

Now, boot up the server using the following command.

nodemon server

Step 6: Run the project.

Start both the server, if not started.

  1. ng server –open
  2. nodemon server

Go to the http://localhost:4200/

Until you have selected any file, the upload an image button will remain disabled.

Upload an image, and see the response you get in the browser console.

Angular Node.js Image Upload

 

I have also written an Angular 8 Image Upload Example in this blog.

You can modify and resize the image on the node.js backend as well. I have also written a tutorial on resizing image using node.js and Express.

Multer API

File information

Each file contains the following information:

Key Description Note
fieldname Field name specified in the form
originalname Name of a file on the user’s computer
encoding Encoding type of the file
mimetype The mime type of the file
size Size of the file in bytes
destination The folder to which a file has been saved DiskStorage
filename The name of the file within the destination DiskStorage
path The full path to the uploaded file DiskStorage
buffer Buffer of the entire file MemoryStorage

 

#multer(opts)

Multer accepts the options object, the most basic of which is a dest property, which tells Multer where to upload the files on the server. If you omit the options object, the files will be kept in the memory and never written on the disk.

By default, Multer will rename the files to avoid naming conflicts. However, the renaming function can be modified according to your needs.

The following are the main options that can be passed to Multer.

Key Description
dest or storage Where to store the files
fileFilter Function to control which files are accepted
limits Limits of the uploaded data
preservePath Keep the full path of the files instead of just a base name

An average web app might only be required and configured, as shown in the following example.

let upload = multer({ dest: uploads/ })

If you need more control over your uploads process, you need to use the storage option instead of the dest option. Multer ships with storage engines DiskStorage and the MemoryStorage; More engines are available from third parties.

.single(fieldname)

Accept a single file with the name called fieldname. The single file will be stored in req.file.

.array(fieldname[, maxCount])

Accept the array of files, all with the name fieldname. Optionally error out if more than files are uploaded. An array of files will be stored in req.files.

.fields(fields)

Accept a mix of files, specified by fields. An object with arrays of files will be stored in req.files.

fields should be an array of objects with name and optionally a maxCount. Example:

[
  { name: avatar, maxCount: 1 },
  { name: gallery, maxCount: 8 }
]

.none()

Accept only text fields. If any file upload is made, an error with code “LIMIT_UNEXPECTED_FILE” will be issued.

.any()

Accepts all files that come over the wire. An array of files will be stored in req.files.

WARNING: Ensure that you always handle the files that a user uploads. Never add multer as a global middleware since a malicious user could upload files to a route you didn’t anticipate. Only use this function on routes where you are handling the uploaded files.

storage

DiskStorage

The disk storage engine gives you full control over storing files on a disk.

// server.js
 let storage = multer.diskStorage({
    destination: function (req, file, cb) {
      cb(null, '/tmp/my-uploads')
    },
    filename: function (req, file, cb) {
      cb(null, file.fieldname + '-' + Date.now())
    }
  })
   
  let upload = multer({ storage: storage })

There are two options available, destination and filename. They are both functions that determine where the file should be stored.

destination is used to determine within which folder the uploaded files should be stored. This can also be given as a string (e.g. '/tmp/uploads'). If no destination is given, the operating system’s default directory for temporary files is used.

Note: You are responsible for creating the directory when providing a destination as a function. When passing a string, multer will ensure that the directory is created for you.

filename is used to determine what the file should be named inside the folder. Each file will be given a random name that doesn’t include any file extension if no one is given.

Note: Multer will not append any file extension for you; your function should return a filename complete with a file extension.

Each function gets passed both the request (req) and some information about the file (file) to aid with the decision.

Note that req.body It might not have been fully populated yet. It depends on how the client transmits fields and files to the server.

#MemoryStorage

The memory storage engine stores the files in memory as Buffer objects. It doesn’t have any options.

var storage = multer.memoryStorage()
var upload = multer({ storage: storage })

When using memory storage, the file info will contain a field called buffer that includes the entire file.

WARNING: Uploading huge files, or relatively small files in large numbers very quickly, can cause your application to run out of memory when memory storage is used.

#limits

An object specifying the size limits of the following optional properties. Multer passes this object into the busboy directly, and the details of the properties can be found on the busboy’s page.

The following integer values are available:

Key Description Default
fieldNameSize Max field name size 100 bytes
fieldSize Max field value size 1MB
fields Max number of non-file fields Infinity
fileSize For multipart forms, the max file size (in bytes) Infinity
files For multipart forms, the max number of file fields Infinity
parts For multipart forms, the max number of parts (fields + files) Infinity
headerPairs For multipart forms, the max number of header key=>value pairs to parse 2000

Specifying the limits can help protect your site against denial of service (DoS) attacks.

#fileFilter

Set this to a function to control which files should be uploaded and skipped. The function should look like this:

// server.js
 function fileFilter (req, file, cb) {
 
    // The function should call `cb` with a boolean
    // to indicate if the file should be accepted
   
    // To reject this file pass `false`, like so:
    cb(null, false)
   
    // To accept the file pass `true`, like so:
    cb(null, true)
   
    // You can always pass an error if something goes wrong:
    cb(new Error('I don\'t have a clue!'))
   
  }

#Error handling

When encountering an error, Multer will delegate the error to Express. Thus, you can display a nice error page using the standard expressway.

If you want to catch errors specifically from Multer, you can call the middleware function yourself. Also, if you’re going to catch only the Multer errors, you can use the MulterError class that is attached to the multer object itself (e.g. err instanceof multer.MulterError).

// server.js
var multer = require('multer')
var upload = multer().single('avatar')
 
app.post('/profile', function (req, res) {
  upload(req, res, function (err) {
    if (err instanceof multer.MulterError) {
      // A Multer error occurred when uploading.
    } else if (err) {
      // An unknown error occurred when uploading.
    }
 
    // Everything went fine.
  })
})

That’s it for this tutorial. Thanks for taking it.

38 thoughts on “Angular File Upload: Angular Image Upload Example”

  1. I watched many tutorials but u r the best.
    i m trying from last 2 weeks but nothing happens. Thanku for this tutorial.

    Can u make a new tutorial on how to show image after save in folder and database

    Reply
  2. bonjour
    great share.
    I think the most stable premium iptv servers are those from Fishbone IPTV cloud
    I would like to see more posts like this
    Thanks

    Reply
  3. I got another issue. after running server.js upload works perfect but I got 404 Err ‘File NOT found’ from another method I already have.

    this.httpClnt.get (‘assets/daily.json’); //it works before running server.js but after running httpClient Get json files not working

    any idea

    Reply
  4. ng build –prod getting error:
    Please consider moving FileSelectDirective in node_modules/ng2-file-upload/file-upload/file-select.directive.d.ts to a higher module that imports AppModule in src/app/app.module.ts and FileUploadModule in node_modules/ng2-file-upload/file-upload/file-upload.module.d.ts. You can also create a new NgModule that exports and includes FileSelectDirective in node_modules/ng2-file-upload/file-upload/file-select.directive.d.ts then import that NgModule in AppModule in src/app/app.module.ts and FileUploadModule in node_modules/ng2-file-upload/file-upload/file-upload.module.d.ts.

    Reply

Leave a Comment

This site uses Akismet to reduce spam. Learn how your comment data is processed.