Ionic 5 Firebase File/Image Upload with Progress Bar Tutorial with Example

Last updated on by Digamber

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 5 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 5 project and precisely target image uploading functionality along with progress indicator. So, let’s get along:

Set up Ionic Environment

First, install Ionic CLI executing the following command:

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=angular

Start the application:

ionic serve

Create Firebase Project + Database Set Up

Head over to console.firebase.google.com, login using email then click on Add project.

Setting up Firebase Project

Declare the project name and click on continue.

Ionic 5 Firebase Auth Tutorial

Next, click on the denoted icon.

Ionic 5 Firebase Auth Tutorial

Next up, provide the App nickname.

Ionic 5 Firebase App Nickname

The credentials which you are seeing copy them we will need them in a moment.

Firebase Config Keys

Then, click on denoted “create database”.

Firebase Realtime Database

Configure the database rules to “start in test mode”.

Ionic 5 Firebase Security

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

Angular Firebase library establish the communication between Firebase and Ionic application, the package is widely known as AngularFire.

Execute the command to install the official Angular library for Firebase.

npm install firebase @angular/fire

Next, register the AngularFire package in Ionic’s main app module.

Add the following code in app.module.ts file:

// app/app.module.ts

import { NgModule } from '@angular/core';
import { BrowserModule } from '@angular/platform-browser';
import { RouteReuseStrategy } from '@angular/router';

import { IonicModule, IonicRouteStrategy } from '@ionic/angular';
import { SplashScreen } from '@ionic-native/splash-screen/ngx';
import { StatusBar } from '@ionic-native/status-bar/ngx';

import { AppComponent } from './app.component';
import { AppRoutingModule } from './app-routing.module';

import { AngularFireModule } from '@angular/fire';
import { AngularFirestoreModule } from '@angular/fire/firestore';
import { AngularFireStorageModule } from '@angular/fire/storage';

import { environment } from '../environments/environment';

@NgModule({
  declarations: [AppComponent],
  entryComponents: [],
  imports: [
    BrowserModule, 
    IonicModule.forRoot(), 
    AppRoutingModule, 
    AppRoutingModule,
    AngularFireModule.initializeApp(environment.firebaseConfig),
    AngularFirestoreModule,
    AngularFireStorageModule
  ],
  providers: [
    StatusBar,
    SplashScreen,
    { 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.component.ts file.

import { Component } from '@angular/core';

import { Observable } from 'rxjs';
import { finalize, tap } from 'rxjs/operators';
import { AngularFireStorage, AngularFireUploadTask } from '@angular/fire/storage';
import { AngularFirestore, AngularFirestoreCollection } from '@angular/fire/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<number>;

  // 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 = 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 => {
            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 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 Button

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.component.html file.

<ion-header [translucent]="true">
  <ion-toolbar>
    <ion-title>
      Ionic 5 Firebase File Upload Demo
    </ion-title>
  </ion-toolbar>
</ion-header>

<ion-content [fullscreen]="true">
  <div id="container">

    <ion-card class="ion-text-center" *ngIf="!isUploading && !isUploaded">
      <ion-card-header>
        <ion-card-title>Choose Images to Upload</ion-card-title>
      </ion-card-header>
      <ion-card-content>
        <ion-button color="primary" shape="round" size="medium">
          <input type="file" (change)="uploadImage($event.target.files)" />
        </ion-button>
      </ion-card-content>
    </ion-card>

  </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:

Ionic 5 Firebase File/Image Upload with Progress Bar Examlpe

Summary

Ultimately, we have completed this tutorial. In this tutorial we have create Image uploading in Ionic 5 application, also learned how to easily store the images in Firebase storage and display file uploading progress with progress bar. I hope you loved this tutorial and share it with others.

You can download the complete code of from GitHub.