In the tutorial, we show how to upload files, download files from Angular 6 Client to Node.js RestAPIs server using Multer middleware.
Related posts:
– NodeJS/Express – Upload/Download MultipartFiles/Images – Multer + JQuery Ajax + Bootstrap
– Node.js RestAPIs – Angular 6 HttpClient – Get/Post/Put/Delete requests + Bootstrap 4
Technologies
- Angular 6
- RxJS 6
- Nodejs – v8.11.3
Overview
We create 2 projects: {Node.js, Angular}
Node.js RestAPIs
– Node.js project exposes RestAPIs to upload/download files:
- router.post(‘/api/file/upload’, upload.single(“file”), fileWorker.uploadFile);
- router.get(‘/api/file/all’, fileWorker.listUrlFiles);
- router.get(‘/api/file/:filename’, fileWorker.downloadFile);
Configure cross-origin
for Angular-Client which running at port: 4200
.
const cors = require('cors') const corsOptions = { origin: 'http://localhost:4200', optionsSuccessStatus: 200 } app.use(cors(corsOptions)) |
Angular 6 Client
Project structure:
upload-file.service
provides methods: push File to Storage and get Files.list-upload.component
gets and displays list of Files.form-upload.component
helps upload File.details-upload.component
is detail for each item in list of Files.
Practice
Node.js RestAPIs
Setting up NodeJS/Express project
Create a folder Node.js-UploadFiles:
mkdir Node.js-UploadFiles cd Node.js-UploadFiles |
Then init NodeJS project:
>npm init This utility will walk you through creating a package.json file. It only covers the most common items, and tries to guess sensible defaults. See `npm help json` for definitive documentation on these fields and exactly what they do. Use `npm install <pkg>` afterwards to install a package and save it as a dependency in the package.json file. Press ^C at any time to quit. package name: (node.js-uploadfiles) version: (1.0.0) description: Node.js RestAPIs to Upload Files entry point: (index.js) server.js test command: git repository: keywords: Node.js,Express,Multer,Upload-Files author: grokonez.com license: (ISC) About to write to C:\nodejs\Node.js-UploadFiles\package.json: { "name": "node.js-uploadfiles", "version": "1.0.0", "description": "Node.js RestAPIs to Upload Files", "main": "server.js", "scripts": { "test": "echo \"Error: no test specified\" && exit 1" }, "keywords": [ "Node.js", "Express", "Multer", "Upload-Files" ], "author": "grokonez.com", "license": "ISC" } Is this ok? (yes) yes |
We need express
, multer
and cors
modules.
– Express is one of the most popular web frameworks for NodeJs which is built on top of Node.js http module, and adds support for routing, middleware, view system etc.
– Multer is a node.js middleware for handling multipart/form-data , which is primarily used for uploading files.
– Cors: a mechanism that uses HTTP headers to tell a browser to let a web application running at one origin (domain) have permission to access selected resources from a server at a different origin.
-> Install Express, Multer & Cors:
npm install express multer cors --save |
-> Check package.json file:
{ "name": "node.js-uploadfiles", "version": "1.0.0", "description": "Node.js RestAPIs to Upload Files", "main": "server.js", "scripts": { "test": "echo \"Error: no test specified\" && exit 1" }, "keywords": [ "Node.js", "Express", "Multer", "Upload-Files" ], "author": "grokonez.com", "license": "ISC", "dependencies": { "cors": "^2.8.4", "express": "^4.16.3", "multer": "^1.3.1" } } |
Config Multer Upload
– Create ./app/config/multer.config.js file:
const multer = require('multer'); var storage = multer.diskStorage({ destination: (req, file, cb) => { cb(null, __basedir + '/uploads/') }, filename: (req, file, cb) => { cb(null, file.originalname) } }); var upload = multer({storage: storage}); module.exports = upload; |
Express Routers
– Create ./app/routers/file.router.js file:
let express = require('express'); let router = express.Router(); let upload = require('../config/multer.config.js'); let fileWorker = require('../controllers/file.controller.js'); router.post('/api/file/upload', upload.single("file"), fileWorker.uploadFile); router.get('/api/file/all', fileWorker.listUrlFiles); router.get('/api/file/:filename', fileWorker.downloadFile); module.exports = router; |
File Controllers
– Create ./app/controllers/file.controller.js file
const uploadFolder = __basedir + '/uploads/'; const fs = require('fs'); exports.uploadFile = (req, res) => { res.send('File uploaded successfully! -> filename = ' + req.file.filename); } exports.listUrlFiles = (req, res) => { fs.readdir(uploadFolder, (err, files) => { for (let i = 0; i < files.length; ++i) { files[i] = "http://localhost:8080/api/file/" + files[i]; } res.send(files); }) } exports.downloadFile = (req, res) => { let filename = req.params.filename; res.download(uploadFolder + filename); } |
Server.js
Implement ./server.js file:
var express = require('express'); var app = express(); const cors = require('cors') const corsOptions = { origin: 'http://localhost:4200', optionsSuccessStatus: 200 } app.use(cors(corsOptions)); global.__basedir = __dirname; let router = require('./app/routers/file.router.js'); app.use('/', router); // Create a Server let server = app.listen(8080, () => { let host = server.address().address let port = server.address().port console.log("App listening at http://%s:%s", host, port); }) |
Angular 6 Client
Generate Service & Components
Run commands below:
ng g s upload/UploadFile
ng g c upload/FormUpload
ng g c upload/ListUpload
ng g c upload/DetailsUpload
On each Component selector, delete app-
prefix, then change tslint.json rules – "component-selector"
to false.
App Module
app.module.ts
->
import { BrowserModule } from '@angular/platform-browser'; import { NgModule } from '@angular/core'; import { HttpClientModule } from '@angular/common/http'; import { AppComponent } from './app.component'; import { DetailsUploadComponent } from './upload/details-upload/details-upload.component'; import { FormUploadComponent } from './upload/form-upload/form-upload.component'; import { ListUploadComponent } from './upload/list-upload/list-upload.component'; @NgModule({ declarations: [ AppComponent, DetailsUploadComponent, FormUploadComponent, ListUploadComponent ], imports: [ BrowserModule, HttpClientModule ], providers: [], bootstrap: [AppComponent] }) export class AppModule { } |
Upload File Service
upload/upload-file.service.ts
->
import { Injectable } from '@angular/core'; import { HttpClient, HttpEvent, HttpRequest } from '@angular/common/http'; import { Observable } from 'rxjs'; @Injectable({ providedIn: 'root' }) export class UploadFileService { constructor(private http: HttpClient) { } pushFileToStorage(file: File): Observable<HttpEvent<{}>> { const formdata: FormData = new FormData(); formdata.append('file', file); const req = new HttpRequest('POST', '/post', formdata, { reportProgress: true, responseType: 'text' }); return this.http.request(req); } getFiles(): Observable<any> { return this.http.get('/getallfiles'); } } |
Component for getting List of Files
upload/list-upload.component.ts
->
import { Component, OnInit } from '@angular/core'; import { Observable } from 'rxjs'; import { UploadFileService } from '../upload-file.service'; @Component({ selector: 'list-upload', templateUrl: './list-upload.component.html', styleUrls: ['./list-upload.component.css'] }) export class ListUploadComponent implements OnInit { showFile = false; fileUploads: Observable<string[]>; constructor(private uploadService: UploadFileService) { } ngOnInit() { } showFiles(enable: boolean) { this.showFile = enable; if (enable) { this.fileUploads = this.uploadService.getFiles(); } } } |
upload/list-upload.component.html
->
<button class="button btn-info" *ngIf='showFile' (click)='showFiles(false)'>Hide Files</button> <button class="button btn-info" *ngIf='!showFile' (click)='showFiles(true)'>Show Files</button> <div [hidden]="!showFile"> <div class="panel panel-primary"> <div class="panel-heading">List of Files</div> <div *ngFor="let file of fileUploads | async"> <div class="panel-body"> <details-upload [fileUpload]='file'></details-upload> </div> </div> </div> </div> |
upload/details-upload.component.ts
->
import { Component, OnInit, Input } from '@angular/core'; @Component({ selector: 'details-upload', templateUrl: './details-upload.component.html', styleUrls: ['./details-upload.component.css'] }) export class DetailsUploadComponent implements OnInit { @Input() fileUpload: string; constructor() { } ngOnInit() { } } |
upload/details-upload.component.html
->
<a href="{{fileUpload}}">{{fileUpload}}</a> |
Component for uploading File
upload/form-upload.component.ts
import { Component, OnInit } from '@angular/core'; import { UploadFileService } from '../upload-file.service'; import { HttpResponse, HttpEventType } from '@angular/common/http'; @Component({ selector: 'form-upload', templateUrl: './form-upload.component.html', styleUrls: ['./form-upload.component.css'] }) export class FormUploadComponent implements OnInit { selectedFiles: FileList; currentFileUpload: File; progress: { percentage: number } = { percentage: 0 }; constructor(private uploadService: UploadFileService) { } ngOnInit() { } selectFile(event) { this.selectedFiles = event.target.files; } upload() { this.progress.percentage = 0; this.currentFileUpload = this.selectedFiles.item(0); this.uploadService.pushFileToStorage(this.currentFileUpload).subscribe(event => { if (event.type === HttpEventType.UploadProgress) { this.progress.percentage = Math.round(100 * event.loaded / event.total); } else if (event instanceof HttpResponse) { console.log('File is completely uploaded!'); } }); this.selectedFiles = undefined; } } |
upload/form-upload.component.html
->
<div *ngIf="currentFileUpload" class="progress"> <div class="progress-bar progress-bar-info progress-bar-striped" role="progressbar" attr.aria-valuenow="{{progress.percentage}}" aria-valuemin="0" aria-valuemax="100" [ngStyle]="{width:progress.percentage+'%'}"> {{progress.percentage}}%</div> </div> <label class="btn btn-default"> <input type="file" (change)="selectFile($event)"> </label> <button class="btn btn-success" [disabled]="!selectedFiles" (click)="upload()">Upload</button> |
App Component
app.component.ts
->
import { Component } from '@angular/core'; @Component({ selector: 'app-root', templateUrl: './app.component.html', styleUrls: ['./app.component.css'] }) export class AppComponent { title = 'JavaSampleApproach'; description = 'Angular-SpringBoot Demo'; } |
app.component.html
->
<div class="container" style="width:400px"> <div style="color: blue; margin-bottom: 20px"> <h1>{{title}}</h1> <h3>{{description}}</h3> </div> <form-upload></form-upload> <br/> <br/> <list-upload></list-upload> </div> |
Check Results
Run Node.js Server (using npm start
) and Angular 6 Client App (using ng serve
)
Then open Browser with url http://localhost:4200/
.
-> Upload files and show list of Files:
-> Inside ‘Node.js-UploadFiles’ project folder, open ‘uploads’ folder:
-> Click to the links to download files:
Sourcecode
Last updated on February 6, 2020.
Hi
please post this source code https://grokonez.com/wp-content/uploads/2018/07/Node.js-Upload-Files-RestAPIs.zip .. looks like link is not available.
Thanks
Anand S
Hi AnandaPadmanaban,
We have updated, please check out!
Regards
Please make tutorial how to upload image for Ionic Framework