Build a Real Time Tutorial App with Ionic & Firebase

We can perform ionic CRUD operation on Firebase in a number of ways. One of the easiest ways is through AngularFire2.  In this tutorial, we will learn how to perform CRUD operation on the Firebase database through firebase javascript package.  

What are we learning?

  1. How to use Firebase  as backend
  2. How to render/upload the record to Firebase
  3. How to upload/read image to Firebase.

Project Screen Shot

 

Step 1: Creating project and adding related plugin

ionic start blank tutorial
$ ionic cordova plugin add cordova-plugin-camera
$ npm install --save @ionic-native/camera
npm install firebase --save

 

Step 2: Configuring Firebase Project
We have to create a project in Firebase for an ionic app we have to select web app. 

 On clicking on the web app we will get API from Firebase project and add copy this code. Then create a new file in app folder as app.firbase.config.ts file and this code as below.

export const FIREBASE_CONFIG = {
    apiKey: "..........",
    authDomain: "..........",
    databaseURL: "..........",
    projectId: "............",
    storageBucket: "..........",
    messagingSenderId: ".........."
};

replace all these dots with your values of API from Firebase. Now we have to import this code app.components.ts as a highlight.

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

import { HomePage } from '../pages/home/home';
import { FIREBASE_CONFIG } from './app.firebase.config';
import firebase from 'firebase';

@Component({
  templateUrl: 'app.html'
})
export class MyApp {
  rootPage:any = HomePage;

  constructor(platform: Platform, statusBar: StatusBar, splashScreen: SplashScreen) {
    platform.ready().then(() => {
      statusBar.styleDefault();
      splashScreen.hide();
      firebase.initializeApp(FIREBASE_CONFIG);
    });
  }
}

 

We can control the Firebase authorization but for this project, we are not adding any authentication. To perform CRUD operation Firebase database we have to set the database rule to the public so that we can access without login.  

 

Step 3: Creating  Interface For our Project

We will create two page, home page for rendering all course and modal page to add a new course and edit old course.

ionic generate page modal

The above image is the screen shot of the home page. We have plus button on the top right corner to add a new course this will called ModalPage. Add the following code in home.html page

<ion-header>
  <ion-navbar>
    <ion-title text-center>Tutorial Courses</ion-title>
    <ion-buttons end>
       <button ion-button icon-only  (click)="addCourse()">
  	  <ion-icon name="add"></ion-icon>
       </button>
    </ion-buttons>
  </ion-navbar>
</ion-header>

<ion-content padding>
  <ion-list>
    <ion-card padding text-wrap *ngFor="let course of courses | async">
      <h2>{{ course.name }}</h2>
      <small>{{ course.level }} ({{ course.duration }})</small>
      <p>{{ course.description }}</p> 
    </ion-card>
  </ion-list>
</ion-content>  

Add the following code in app/pages/modals/modals.ts file

The screen shot of modals.html 

<ion-header>
  <ion-toolbar>
    <ion-title>Course Infomation</ion-title>
    <ion-buttons start>
      <button ion-button color="primary" (click)="closeModal()">
        <span showWhen="ios">Cancel</span>
      <ion-icon name="md-close" showWhen="android,windows"></ion-icon>
      </button>
    </ion-buttons>
  </ion-toolbar>
</ion-header>

<ion-content>
  <form [formGroup]="form" (ngSubmit)="saveCourse(form.value)">
    <ion-card>
      <ion-item>
         <ion-label stacked>Course name:</ion-label>
         <ion-input type="text" formControlName="name" [(ngModel)]="courseName"></ion-input>
      </ion-item>

      <ion-item>
         <ion-label stacked>Course Levele:</ion-label>
         <ion-select formControlName="level" [(ngModel)]="courseLevel">
             <ion-option value="Beginner">Beginner Level</ion-option>
             <ion-option value="Intermediate">Intermediate Level</ion-option>
             <ion-option value="Advanced">Advanced Level</ion-option>
             <ion-option value="All">All Level</ion-option>
         </ion-select>
   	  </ion-item>
      <ion-item>
        <ion-label stacked>Course length:</ion-label>
        <ion-input type="text" formControlName="duration" [(ngModel)]="curseDuration"></ion-input>
      </ion-item>

      <ion-item>
         <ion-label stacked>Description:</ion-label>
         <ion-textarea rows="6" formControlName="description" [(ngModel)]="courseDescription"></ion-textarea>
   	  </ion-item>
      <button ion-button color="primary" type="submit" block>Add Course DB</button>
    </ion-card>
  </form>
</ion-content>



Step 4: Adding Course Model
Create new folder models in app folder and add new file course.ts file. Add the following code in app/models/course.ts file.

export interface Course{
    name: string;
    level: any,
    duration: string,
    description: any
}

 

Step 5: Adding Service Provider for Firebase.

ionic generate provider database
ionic generate provider preloader

We have to create database code to perform CRUD operation on Firebase and we will add following code in loader file called app/providers/preloader.ts

import { Injectable } from '@angular/core';
import { LoadingController } from 'ionic-angular';
import { Http } from '@angular/http';
import 'rxjs/add/operator/map';

@Injectable()
export class Preloader {

   private loading : any;

   constructor( public http: Http, public loadingCtrl: LoadingController){}

   displayPreloader() : void{
      this.loading = this.loadingCtrl.create({
         content: 'Please wait...'
      });
      this.loading.present();
   }

   hidePreloader() : void {
      this.loading.dismiss();
   }

}

 

In database.ts file we are adding two methods one for adding new course information to Firebase and other to render all the existing record in firebase. Add the following code in app/providers/database.ts file

import { Injectable } from '@angular/core';
import { ViewController, AlertController } from 'ionic-angular';
import { Http } from '@angular/http';
import 'rxjs/add/operator/map';
import { Observable } from "rxjs/Observable";
import * as firebase from 'firebase';


@Injectable()
export class Database {

  constructor(public http: Http, public alertCtrl: AlertController){}

  renderCourses() : Observable<any>{
    try {
      return new Observable(observer => {
        let courses : any = [];
        firebase.database().ref('courses').orderByKey().once('value', (items : any) => {
          items.forEach((item) => {
            courses.push(item.val());
          });

          observer.next(courses);
          observer.complete();
        },
        (error) => {
              console.log("Observer error: ", error);
              console.dir(error);
              observer.error(error)
        });

      });
    }
    catch(error){
         console.log('Observable for retrieving courses fails');
         console.dir(error);
    }
  }

   
  addToDatabase(courseObj) : Promise<any> {
    return new Promise((resolve) => {
      let addRef = firebase.database().ref('courses');
        addRef.push(courseObj);
        resolve(true);
    });
   }
}

Once we create these two providers then we have added this provider reference in app.module.ts

 

Step 6: Adding typescript code in home and modals page.

We have already added User interface for both home and modal page. Add the following code to home.ts file

import { Component, Input } from '@angular/core';
import { NavController, Platform, ModalController } from 'ionic-angular';
import { ModalsPage } from '../modals/modals';
import { Preloader} from '../../providers/preloader';
import { Database } from '../../providers/database';


@Component({
  selector: 'page-home',
  templateUrl: 'home.html'
})
export class HomePage {

  public courses: any;
  constructor(public navCtrl: NavController, private platform: Platform, private _DB: Database, public modalCtrl: ModalController, private _LOADER : Preloader) {}

   ionViewDidEnter(){
      this._LOADER.displayPreloader();
      this.platform.ready()
      .then(() => {
            this.loadAndParseCourses();
      })
      .catch((err : Error) =>{
        console.log(err.message);
      });
   }


   loadAndParseCourses(){
      this.courses = this._DB.renderCourses();
      this._LOADER.hidePreloader();
   }

   addCourse(){
     let modal = this.modalCtrl.create(ModalsPage);
     modal.onDidDismiss((data) => {
        this._LOADER.displayPreloader();
        this.loadAndParseCourses();
     });
     modal.present();
   }
}

 

In home.ts file we have import  ModalController from ionic-angular library, as for editing and adding the new course we will call modalPage.  A Modal is a content pane that goes over the user’s current page. Add the following code in app/pages/modals/modals.ts file

import { Component } from '@angular/core';
import { IonicPage, ViewController, AlertController} from 'ionic-angular';
import { FormBuilder, Validators } from '@angular/forms';
import { Camera, CameraOptions } from 'ionic-native';
import { Photo } from '../../providers/photo';
import { Preloader } from '../../providers/preloader';
import { Database } from '../../providers/database';
import * as firebase from 'firebase';
import { Course } from '../../models/course'

@IonicPage()
@Component({
  selector: 'page-modals',
  templateUrl: 'modals.html',
})

export class ModalsPage {
  course = {} as Course;
  public form : any;
  public courses: any;

  public courseId : String = '';
  public courseName: any = '';
  public courseDescription: any = '';
  public courseLevel: any;
  public courseImage: any;

  public courseDuration : string ='';

  constructor( public viewCtrl: ViewController, private alertCtrl: AlertController, private _FB: FormBuilder, private _photo: Photo,private _LOADER: Preloader, private _DB: Database) {
    this.form = _FB.group({
      'name'  : ['', Validators.required],
      'level' : ['', Validators.required],
      'duration' : ['', Validators.required],
      'description' : ['', Validators.required]
    });

    this.courses = firebase.database().ref('courses/');
  }


  saveCourse(val){
    this.course.name = this.form.controls["name"].value;
    this.course.level = this.form.controls["level"].value + 'Level';
    this.course.duration = this.form.controls["duration"].value;
    this.course.description = this.form.controls["description"].value;
  
    this._DB.addToDatabase(this.course)
      .then((data) =>{
        this.showSuccesfulUploadAlert();
        this._LOADER.hidePreloader();
      });
    this.closeModal(true);
  }

  closeModal(val = null){
    this.viewCtrl.dismiss();
  }

  
  showSuccesfulUploadAlert() {
    let alert = this.alertCtrl.create({
      title: 'Uploaded!',
      subTitle: 'Course  is uploaded to Firebase',
      buttons: ['OK']
    });
    alert.present();
    // clear the previous photo data in the variable
  }
}