Ionic Tutorials

Ionic 6 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

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

Disable Strict Type Errors

To get rid from strict type warnings or errors ensure that you set “strictTemplates”: false under angularCompilerOptions in tsconfig.json file.

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.

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

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

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:

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],
  entryComponents: [],
  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<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 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

Ultimately, we have completed this tutorial. In this tutorial we have create Image uploading in Ionic application, also learned how to easily store the images in Firebase storage and display file uploading progress with progress bar.

Digamber

I am Digamber, a full-stack developer and fitness aficionado. I created this site to bestow my coding experience with newbie programmers. I love to write on JavaScript, ECMAScript, React, Angular, Vue, Laravel.

Recent Posts

React Redux Handle API Calls with Thunk Middleware Tutorial

In this post, we will learn how to work with HTTP requests in the Redux…

1 day ago

Node AJAX Retrieve Records from MySQL Database Tutorial

MySQL is a relational database management system based on SQL – Structured Query Language, and…

4 days ago

React Manage REST API State Globally with Context API Tutorial

React Js Handle Rest API data globally with Context and useState hook tutorial. In this…

1 week ago

How to Delete Data from MySQL Database using Node Js

Node js delete data from MySQL database tutorial; Throughout this guide, you will ascertain how…

1 week ago

Node Import CSV File Data to MySQL Database with HTML Form

In this tutorial, you will discover how to import CSV file into MySQL database using…

2 weeks ago

How to Handle Global State in React js using Context API

React Js Global state management with createContext hook example; In this tutorial, we will help…

2 weeks ago