In this lesson, we will provide a solution to upload multiple files and images to server with angular as a client. We will be creating a sample Angular project and define a file component and hit REST endpoint to upload files. There will be an option either to select files from local PC or drag and drop the file from PC to browser and upload them in one shot. For demo purpose, the server will be a spring boot based server. We will be using MultipartFile as RequestParam in spring controller and in the client side we will be using ng2-file-upload and HTML5 FormData.

We will be using Angular CLI to generate our client project. While writing this article, the latest version of Angular is 7 and we will make use of it but the implementation will equally work for Angular 4, Angular 5 and Angular 6. We will make use of FileSelectDirective and FileDropDirective from ng2-file-upload to achieve this example.

Generating Angular Project

In this article, we won't be discussing the setting up Angular environment. For all those implementations and many more, you can visit my Angular 7 CRUD article. Below are the commands to execute to get started with our Angular project.

ng new angular-file-upload cd angular-file-upload npm i ng2-file-upload --save ng g component file-upload ng add @angular/material

Above commands will generate a new Angular project and adds ng2-file-upload and material designing to it. It also adds our file upload component to it. Now we can import this project into IDE and below will be the final project structure.

App Module Implementation

We have imported all the required modules here. All the modules imported here are the common modules that we import while creating an Angular project. One thing to notice here is the FileSelectDirective from ng2-file-upload in the declarations. If you do not import this in the declarations section, then there will be a template parse error as Can't bind to 'uploader' since it isn't a known property of 'input'.

In the routing configuration, we have defined a default route for FileUploadComponent.

import { BrowserModule } from '@angular/platform-browser' ; import { NgModule } from '@angular/core' ; import { AppComponent } from './app.component' ; import { FileUploadComponent } from './file-upload/file-upload.component' ; import {RouterModule} from "@angular/router" ; import {FormsModule, ReactiveFormsModule} from "@angular/forms" ; import {FileSelectDirective} from "ng2-file-upload" ; import {HttpClientModule} from "@angular/common/http" ; import {CustomMaterialModule} from "./file-upload/material.module" ; import { BrowserAnimationsModule } from '@angular/platform-browser/animations' ; @NgModule ({ declarations : [ AppComponent, FileUploadComponent, FileSelectDirective ], imports : [ BrowserModule, RouterModule, FormsModule, ReactiveFormsModule, HttpClientModule, CustomMaterialModule, RouterModule.forRoot([ {path: '', component: FileUploadComponent} ]), BrowserAnimationsModule ], providers : [], bootstrap: [AppComponent] }) export class AppModule { }

File Upload Component Implementation

Below is the implementation of our file-upload.component.html . Here, we have a drop-down that provides an option to select the type of image to upload and then we have use of ng2FileSelect directive. Here, we are using restriction of .png file to upload but you can restrict it for other files too such as .csv etc. The input type that we have defined here supports multiple file upload. We also have a functionality to drag and drop files directly on the browser window from the PC and the file will be automatically uploaded.

It also has an implementation of table. This table is used show the name of the file that you have uploaded and also provides an icon to remove the uploaded file. Overall, the implementation is very dynamic and thanks to valor-software for providing this implementation.

<h4>Welcome to {{ title }}!</h4> <mat-card> <form [formGroup]="uploadForm" (ngSubmit)="uploadSubmit()"> <mat-card-content> <mat-form-field class="form-field"> <mat-label>Select Document Type</mat-label> <mat-select formControlName="type" required> <mat-option value="Passport">Passport</mat-option> <mat-option value="Driving_license">Driving License</mat-option> <mat-option value="PAN">PAN</mat-option> </mat-select> </mat-form-field> <br> <input formControlName="document" type="file" ng2FileSelect accept=".png" [uploader]="uploader" multiple/><br/> <br> <div class="drop-zone"> <div ng2FileDrop [uploader]="uploader" class="drop-zone"> Drag and drop files to upload </div> </div> <table> <thead> <tr> <th width="90%"> File Name </th> <th width="10%"> Remove </th> </tr> </thead> <tbody> <tr *ngFor="let item of uploader.queue"> <th width="90%"> {{ item.file.name}}({{item.file.size/1000000}} MB) </th> <th class="text-center" width="10%"> <mat-icon (click)="item.remove()">delete</mat-icon> </th> </tr> </tbody> </table> <br> <button mat-raised-button color="accent" [disabled]="!uploadForm.valid" type="submit">Upload Data</button> </mat-card-content> </form> </mat-card>

In the below implementation, uploadSubmit() validates the file size first and reads all the files from the queue and adds all the files in the Formdata and makes API call to upload the files.

import { Component, OnInit } from '@angular/core' ; import {FormBuilder, FormGroup, Validators} from "@angular/forms" ; import {FileUploader} from "ng2-file-upload" ; import {Observable} from "rxjs" ; import {HttpClient} from "@angular/common/http" ; @Component ({ selector: 'app-file-upload' , templateUrl: './file-upload.component.html' , styleUrls: [ './file-upload.component.css' ] }) export class FileUploadComponent implements OnInit { uploadForm: FormGroup; public uploader:FileUploader = new FileUploader({ isHTML5: true }); title: string = 'Angular File Upload'; constructor (private fb: FormBuilder, private http: HttpClient ) { } uploadSubmit(){ for (let i = 0; i < this.uploader.queue.length; i++) { let fileItem = this.uploader.queue[i]._file; if(fileItem.size > 10000000){ alert("Each File should be less than 10 MB of size."); return; } } for (let j = 0; j < this.uploader.queue.length; j++) { let data = new FormData(); let fileItem = this.uploader.queue[j]._file; console.log(fileItem.name); data.append('file', fileItem); data.append('fileSeq', 'seq'+j); data.append( 'dataType', this.uploadForm.controls.type.value); this.uploadFile(data).subscribe(data => alert(data.message)); } this .uploader.clearQueue(); } uploadFile(data: FormData): Observable { return this.http.post ( 'http://localhost:8080/upload' , data); } ngOnInit() { this .uploadForm = this .fb.group({ document: [null, null], type: [null, Validators.compose([Validators.required])] }); } }

REST API Implementation

Blow is the snippet of the controller class. The method uploadFile() will execute against the API call that we make from the angular client. For an end-to-end implementation of this spring boot app, you can visit my another article here - Angular JS File Upload

@RequestMapping ( value = ( "/upload" ), headers = "content-type=multipart/form-data" , method = RequestMethod.POST) public ApiResponse uploadFile( @RequestParam ( "file" ) MultipartFile file, @RequestParam( "dataType" ) String dataType) { System. out .println(file.getOriginalFilename()); System. out .println(dataType); return new ApiResponse(HttpStatus.OK, "File uploaded successfully." ); }

Testing the Application

Below is the final screenshot of the UI that we created above where you can upload or drag and drop multiple files.

Conclusion

In this article, we created an Angular 7 client application that allows multiple files uploading and enables drag and drop feature for file uploading. You can download the source code of this implementation on GItLab here.