Multiple Image Upload with Ionic 6 and FormData
In this tutorial, you'll learn to implement multiple file upload with Ionic 6, django 3 and FormData.
In a previous tutorial, we've created a django 3 RESTful application for uploading files using django 3 REST framework and Ionic 6.
Also check out how to upload images to TypeScript/Node server using Ionic 6 and FormData
Since the backend code will be the same as we only need an /upload
endpoint that accepts POST requests we'll simply clone the previous and start our django 3 REST API server using the following command:
$ cd ~/demos
$ mkdir ionic-file-upload
$ cd ionic-file-upload
$ git clone https://github.com/techiediaries/django-rest-file-upload.git backend
Next, create and activate a virtual environment using the following commands:
$ cd backend
$ python3 -m venv .env
$ source .env/bin/activate
Next, install the Python packages used in the project:
$ pip install -r requirements.txt
You can then start the development server using:
$ python manage.py makemigrations
$ python manage.py migrate
$ python manage.py runserver
Your RESTful django 3 server will be available from the 127.0.0.1:8000
address.
Here is some information about our restful server:
- It exposes an
/upload
endpoint which accepts POST requests for uploading files. - It has CORS enabled so you can send requests from different doamins without getting blocked by the Same Origin Policy.
Prerequisites
This tutorial makes use of Ionic 6 with Angular and TypeScript so you need to the following prerequisites:
- Node.js and npm installed on your system. You can simply head to the official website and get the binaries for your operating system.
- Working knowledge of TypeScript and Angular.
Now, let's get started!
Installing Ionic CLI v6
Let's install Ionic CLI 6 which is required to generate Ionic 6 projects. Open a new terminal and run the following command:
$ npm install -g @ionic/cli
Note: You many need to add
sudo
before your command in linux (debian-based) and macOS systems to install npm modules globally. Otherwise you simply to fix your npm permissions.
Generating your Ionic 6 Project
Next, you can generate a project based on Angular by running the following command:
$ ionic start
The CLI will interactively prompt you for some information about your project such as the name (Enter fileuploadapp or any name you choose) and the starter template (Select blank which will give you a starting project with a single page)
Next type Enter!
The CLI will start generating the files and installing the dependencies from npm. When prompted if you want to Install the free Ionic Appflow SDK and connect your app? (Y/n) Just type n for now.
Importing HttpClientModule
We'll need to use HttpClient
to send a POST for uploading files to the RESTful server so we need to import HttpClientModule
in our application module. Open the src/app/app.module.ts
file and the following changes:
// [...]
import { HttpClientModule } from '@angular/common/http';
@NgModule({
declarations: [AppComponent],
entryComponents: [],
imports: [/* ... */, HttpClientModule],
providers: [
StatusBar,
SplashScreen,
{ provide: RouteReuseStrategy, useClass: IonicRouteStrategy }
],
bootstrap: [AppComponent]
})
export class AppModule {}
Generating an Uploading Service
After creating the project, let's start our journey by creating a service that encapsulates the code for uploading files to the django 3 server. In your terminal, navigate to your project's root folder and and generate the service using the following commands:
$ cd ./fileuploadapp
$ ionic generate service uploading
You will get the following output:
> ng generate service uploading
CREATE src/app/uploading.service.spec.ts (348 bytes)
CREATE src/app/uploading.service.ts (138 bytes)
[OK] Generated service!
Open the src/app/uploading.service.ts
and change the code accordingly:
import { Injectable } from '@angular/core';
import { HttpClient } from '@angular/common/http';
@Injectable({
providedIn: 'root'
})
export class UploadingService {
DJANGO_API_SERVER: string = "http://localhost:8000";
constructor(private http: HttpClient) { }
public uploadFormData(formData) {
return this.http.post<any>(`${this.DJANGO_API_SERVER}/upload/`, formData);
}
}
Generating an Ionic Page
Let's now generate an Ionic page for adding the upload UI. In your terminal, run the following command:
$ ionic generate page upload
The output of this command will be:
> ng generate page upload
CREATE src/app/upload/upload.module.ts (543 bytes)
CREATE src/app/upload/upload.page.scss (0 bytes)
CREATE src/app/upload/upload.page.html (133 bytes)
CREATE src/app/upload/upload.page.spec.ts (691 bytes)
CREATE src/app/upload/upload.page.ts (256 bytes)
UPDATE src/app/app-routing.module.ts (451 bytes)
[OK] Generated page!
You can access this page from 127.0.0.1:4200/upload
.
Installing and Setting up ng2-file-upload
We'll make use of the ng2-file-upload
package which provides some directives for handling file upload in Angular. First install the package from npm using the following command
$ npm install --save ng2-file-upload
Next, you will need to import FileUploadModule
in your page module. Open the src/app/upload/upload.module.ts
file and the add these changes:
import { NgModule } from '@angular/core';
import { CommonModule } from '@angular/common';
import { FormsModule } from '@angular/forms';
import { Routes, RouterModule } from '@angular/router';
import { IonicModule } from '@ionic/angular';
import { UploadPage } from './upload.page';
import { FileUploadModule } from 'ng2-file-upload';
const routes: Routes = [
{
path: '',
component: UploadPage
}
];
@NgModule({
imports: [
CommonModule,
FormsModule,
IonicModule,
RouterModule.forChild(routes),
FileUploadModule
],
declarations: [UploadPage]
})
export class UploadPageModule {}
Open the src/app/upload/upload.page.ts
file and add the following imports:
// [...]
import { UploadingService } from '../uploading.service';
import { FileUploader, FileLikeObject } from 'ng2-file-upload';
import { concat } from 'rxjs';
Next, define the following variables:
export class UploadPage implements OnInit {
public fileUploader: FileUploader = new FileUploader({});
public hasBaseDropZoneOver: boolean = false;
Next, inject UploadingService
:
export class UploadPage implements OnInit {
constructor(private uploadingService: UploadingService) { }
Next, add the following methods:
fileOverBase(event): void {
this.hasBaseDropZoneOver = event;
}
getFiles(): FileLikeObject[] {
return this.fileUploader.queue.map((fileItem) => {
return fileItem.file;
});
}
uploadFiles() {
let files = this.getFiles();
let requests = [];
files.forEach((file) => {
let formData = new FormData();
formData.append('file' , file.rawFile, file.name);
requests.push(this.uploadingService.uploadFormData(formData));
});
concat(...requests).subscribe(
(res) => {
console.log(res);
},
(err) => {
console.log(err);
}
);
}
Next, open the src/app/upload/upload.page.html
file and the following code:
<ion-header>
<ion-toolbar color="primary">
<ion-title>Upload Page</ion-title>
</ion-toolbar>
</ion-header>
<ion-content color="dark" padding>
<div ng2FileDrop [ngClass]="{'drop-file-over': hasBaseDropZoneOver}" (fileOver)="fileOverBase($event)" [uploader]="fileUploader"
class="area">
<div id="dropZone">Drop files here</div>
</div>
<input type="file" accept="image/*" ng2FileSelect [uploader]="fileUploader" multiple />
<ion-button (click)="uploadFiles()">Upload files</ion-button>
<h2>Your files: {{ fileUploader?.queue?.length }}</h2>
<ul>
<li *ngFor="let item of fileUploader.queue">
{{ item?.file?.name }}
</li>
</ul>
</ion-content>
Next, open the src/app/upload/upload.page.scss
file and add these styles:
.area {
width: 95%;
padding: 15px;
margin: 15px;
border: 1px solid #333;
background: rgba(0,0,0,0.7);
}
#dropZone {
border: 2px dashed #bbb;
-webkit-border-radius: 5px;
border-radius: 5px;
padding: 50px;
text-align: center;
font: 21pt bold arial;
color: #bbb;
}
.drop-file-over{
background: #333;
}
This is a screenshot of the page:
Finally, start your development server using:
$ ionic serve
Head over to the 127.0.0.1:8100
address then select and drop some files and click on the UPLOAD FILES button:
-
Date: