Ionic 7 Firebase File Upload with Progress Bar Tutorial
If you are a novice developer and want to see how Ionic and Firebase work together, this tutorial is for you.
In this tutorial, we will learn how to create a file uploading service in Ionic and store the file/image in Firebase storage.
You will also learn how to display the file/image uploading file uploading progress with a progress bar.
Firebase is a powerful, flexible and user-friendly database that takes care of almost every problem of yours.
Firebase development paradigm is one of the best; it has an innumerable number of features that make your life easy.
Such as File Storage, Authentication, Hosting, Testing, and many more.
Not just that, but you can also develop highly scalable apps with the following features:
- Email & password, Google, Facebook, and Github authentication
- Ready-made API
- Realtime data
- Robust security
- Static file hosting
- File storage supported by Google Cloud Storage
We will create an Ionic project and precisely target image uploading functionality along with progress indicator. So, let’s get along:
Set up Ionic Environment
This tutorial assumes that you have already updated to minimum Node 18, and Ionic 7. Make sure to update your development environment as per the mentioned requirement.
First, install Ionic CLI executing the following command:
sudo npm install -g @ionic/cli
Verify Ionic CLI installation:
ionic --version
Start creating a brand new Ionic project:
ionic start ionic-firebase-file-upload blank --type=angular
Get inside the project:
cd ionic-firebase-file-upload
Run the below command to add the native core package.
npm install @ionic-native/core --legacy-peer-deps
Disable Strict Type Errors
To avoid TypeScript compiling issues, we just need to open tsconfig.json file:
First, set below property under “compilerOptions” property.
"compilerOptions": {
"strictPropertyInitialization": false,
"skipLibCheck": true
...
}
Secondly, add given props under “angularCompilerOptions”.
"angularCompilerOptions": {
"strictTemplates": false,
...
}
Create Firebase Project + Database Set Up
Head over to console.firebase.google.com, login using email then click on Add project.
Declare the project name and click on continue.
Next, click on the denoted icon.
Next up, provide the App nickname.
Copy the Firebase credentials that you are seeing on the screen, keep the details in a notepad.
We’ll need these credentials later to establish the consensus between Ionic Angular and Firebase database.
Then, click on the “Firestore” menu item.
Configure the database rules and set it “test mode”.
Configure Firebase Storage
We might get the permission denied error, to fix this issue, click on the storage -> Rules and replace the existing security rules with the following rule and then click on the publish button.
rules_version = '2';
service firebase.storage {
match /b/{bucket}/o {
match /{allPaths=**} {
allow read, write: if request.auth == null;
}
}
}
Register firebase credentials into the Ionic Angular environment file. Add the following code in environment.ts file.
// environments/environment.ts
export const environment = {
production: false,
firebaseConfig: {
apiKey: "xxxxxx-xxxxxx_xxxxxxxxxxxxxxxxxx",
authDomain: "xxxxxx_xxxxxxxxxxxxxxxxxx",
databaseURL: "xxxxxx_xxxxxxxxxxxxxxxxxx",
projectId: "xxxxxx_xxxxxxxxxxxxxxxxxx",
storageBucket: "xxxxxx_xxxxxxxxxxxxxxxxxx",
messagingSenderId: "xxxxxxxxxxxxxxxxxx",
appId: "1:xxxxxxxxxxxxxxxxxx:web:xxxxxxxxxxxxxxxxxx"
}
};
Install and Configure Angular Firebase Package in Ionic
Execute the command to install the official Angular library for Firebase.
npm install @angular/fire firebase@9.16.0 --legacy-peer-deps
Next, register the AngularFire package in Ionic’s main app module.
Add the following code in app.module.ts file:
import { NgModule } from '@angular/core';
import { BrowserModule } from '@angular/platform-browser';
import { RouteReuseStrategy } from '@angular/router';
import { IonicModule, IonicRouteStrategy } from '@ionic/angular';
import { AppComponent } from './app.component';
import { AppRoutingModule } from './app-routing.module';
// Firebase + environment
import { AngularFireModule } from '@angular/fire/compat';
import { AngularFireStorageModule } from '@angular/fire/compat/storage';
import { AngularFirestoreModule } from '@angular/fire/compat/firestore';
import { environment } from '../environments/environment';
@NgModule({
declarations: [AppComponent],
imports: [
BrowserModule,
IonicModule.forRoot(),
AppRoutingModule,
AngularFireModule.initializeApp(environment.firebaseConfig),
AngularFirestoreModule,
AngularFireStorageModule,
],
providers: [{ provide: RouteReuseStrategy, useClass: IonicRouteStrategy }],
bootstrap: [AppComponent],
})
export class AppModule {}
Build Image Uploading Feature
Now every thing has been configured, let’s start building Ionic/Angular image uploading functionality with Firebase.
We are using the default home component to integrate the file uploading feature, so add the following code in the home.page.ts file.
import { Component } from '@angular/core';
import { Observable } from 'rxjs';
import { finalize, tap } from 'rxjs/operators';
import {
AngularFireStorage,
AngularFireUploadTask,
} from '@angular/fire/compat/storage';
import {
AngularFirestore,
AngularFirestoreCollection,
} from '@angular/fire/compat/firestore';
export interface imgFile {
name: string;
filepath: string;
size: number;
}
@Component({
selector: 'app-home',
templateUrl: 'home.page.html',
styleUrls: ['home.page.scss'],
})
export class HomePage {
// File upload task
fileUploadTask: AngularFireUploadTask;
// Upload progress
percentageVal: Observable<any>;
// Track file uploading with snapshot
trackSnapshot: Observable<any>;
// Uploaded File URL
UploadedImageURL: Observable<string>;
// Uploaded image collection
files: Observable<imgFile[]>;
// Image specifications
imgName: string;
imgSize: number;
// File uploading status
isFileUploading: boolean;
isFileUploaded: boolean;
private filesCollection: AngularFirestoreCollection<imgFile>;
constructor(
private afs: AngularFirestore,
private afStorage: AngularFireStorage
) {
this.isFileUploading = false;
this.isFileUploaded = false;
// Define uploaded files collection
this.filesCollection = afs.collection<imgFile>('imagesCollection');
this.files = this.filesCollection.valueChanges();
}
uploadImage(event: FileList) {
const file: any = event.item(0);
// Image validation
if (file.type.split('/')[0] !== 'image') {
console.log('File type is not supported!');
return;
}
this.isFileUploading = true;
this.isFileUploaded = false;
this.imgName = file.name;
// Storage path
const fileStoragePath = `filesStorage/${new Date().getTime()}_${file.name}`;
// Image reference
const imageRef = this.afStorage.ref(fileStoragePath);
// File upload task
this.fileUploadTask = this.afStorage.upload(fileStoragePath, file);
// Show uploading progress
this.percentageVal = this.fileUploadTask.percentageChanges();
this.trackSnapshot = this.fileUploadTask.snapshotChanges().pipe(
finalize(() => {
// Retreive uploaded image storage path
this.UploadedImageURL = imageRef.getDownloadURL();
this.UploadedImageURL.subscribe(
(resp) => {
this.storeFilesFirebase({
name: file.name,
filepath: resp,
size: this.imgSize,
});
this.isFileUploading = false;
this.isFileUploaded = true;
},
(error) => {
console.log(error);
}
);
}),
tap((snap: any) => {
this.imgSize = snap.totalBytes;
})
);
}
storeFilesFirebase(image: imgFile) {
const fileId = this.afs.createId();
this.filesCollection
.doc(fileId)
.set(image)
.then((res) => {
console.log(res);
})
.catch((err) => {
console.log(err);
});
}
}
Build Custom File Size Pipe Filter
Next, we need to create the custom pipe filter, it will transform file size data and make it readable. Create home/format-file-size.pipe.ts file within the home directory.
import {Pipe, PipeTransform} from '@angular/core';
const FILE_SIZE_UNITS = ['B', 'KB', 'MB', 'GB', 'TB', 'PB', 'EB', 'ZB', 'YB'];
const FILE_SIZE_UNITS_LONG = ['Bytes', 'Kilobytes', 'Megabytes', 'Gigabytes', 'Pettabytes', 'Exabytes', 'Zettabytes', 'Yottabytes'];
@Pipe({
name: 'formatFileSize'
})
export class FormatFileSizePipe implements PipeTransform {
transform(sizeInBytes: number, longForm: boolean): string {
const units = longForm
? FILE_SIZE_UNITS_LONG
: FILE_SIZE_UNITS;
let power = Math.round(Math.log(sizeInBytes)/Math.log(1024));
power = Math.min(power, units.length - 1);
const size = sizeInBytes / Math.pow(1024, power); // size in new units
const formattedSize = Math.round(size * 100) / 100; // keep up to 2 decimals
const unit = units[power];
return `${formattedSize} ${unit}`;
}
}
Next, import and register the FormatFileSizePipe custom pipe filter in home.module.ts file.
import { NgModule } from '@angular/core';
import { CommonModule } from '@angular/common';
import { IonicModule } from '@ionic/angular';
import { FormsModule } from '@angular/forms';
import { HomePage } from './home.page';
import { HomePageRoutingModule } from './home-routing.module';
import { FormatFileSizePipe } from './format-file-size.pipe';
@NgModule({
imports: [
CommonModule,
FormsModule,
IonicModule,
HomePageRoutingModule
],
declarations: [
HomePage,
FormatFileSizePipe
]
})
export class HomePageModule {}
Create File Upload aButton
This step tells you how to create File uploading button and bind the functions to upload and store file in cloud firestore storage.
Add the following code in home.page.html file.
<ion-header [translucent]="true">
<ion-toolbar>
<ion-title> Ionic Firebase File Upload Demo </ion-title>
</ion-toolbar>
</ion-header>
<ion-content>
<ion-card class="ion-text-center" *ngIf="!isFileUploading && !isFileUploaded">
<ion-card-header>
<ion-card-title>Choose Images to Upload</ion-card-title>
</ion-card-header>
<ion-card-content>
<ion-button color="primary" size="medium">
<input type="file" (change)="uploadImage($event.target.files)" />
</ion-button>
</ion-card-content>
</ion-card>
<!-- File upload progress bar -->
<div *ngIf="percentageVal | async as percentage">
Progress: {{ percentage | number }}%
<ion-progress-bar value="{{ percentage / 100 }}"></ion-progress-bar>
</div>
<div *ngIf="trackSnapshot | async as snap">
File size: {{ snap.totalBytes | formatFileSize }} Data transfered: {{
snap.bytesTransferred | formatFileSize }}
</div>
</ion-content>
Start Project
Eventually, we need to test the Ionic image uploading feature. So, run the following command and start the application.
npm install --save-dev @ionic/lab
Open the app:
ionic serve -l
The final output:
Summary
In this tutorial we have learned how to create Image uploading with progress bar functionality in Ionic application.
We have also seen how to easily store the images in Firebase storage and display file uploading progress with progress bar component.