Ionic Uploading Image from Gallery to Firebase

Firebase allows us to upload an image. Here we are learning how to upload a photo from the photo gallery to Firebase server.

 

Step 1: Setting up Apps 

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

 

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 this code and import firebase in app.components.ts as a highlight.

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

import { HomePage } from '../pages/home/home';
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();

      const firebaseConfig = {
        apiKey: "....",
        authDomain: "cam....,
        databaseURL: "h....",
        projectId: "camera.....",
        storageBucket: "camera.....",
        messagingSenderId: "933..."
      };
      
      firebase.initializeApp(firebaseConfig);
    });
  }
}

By default we need authentication to use storage in Firebase, so for this example, we are not using any authentication. We have to change the storage rule as

 

Step 2: Adding user interface for Apps

Add the following code in home.ts file, we will create a button to take an image from the photo gallery.

<ion-header>
  <ion-navbar>
    <ion-title>
      Camera Image Upload
    </ion-title>
  </ion-navbar>
</ion-header>

<ion-content padding>
  <ion-row class="center">
      <button ion-button (click)="getPicture(0)">Show Album</button>  
  </ion-row>
  <ion-card>
    <img [src]="captureDataUrl" *ngIf="captureDataUrl"/>
    <button ion-button (click)="upload()" *ngIf="captureDataUrl">Upload to Firebase!</button>
  </ion-card>
</ion-content>  

 

Step 3:  Adding code for uploading photo to firebase

The getPicture(sourceType) method we are passing zero as an argument, as in camera option, source type zero is for selecting an image from gallery and getPicture(1) for selecting the photo from the camera.

To upload photo, we will first need to get the root storage reference via firebase.storage().ref(). After that, we need to set file path in Firebase Storage. In this app, we have defined that all pictures must be inside a path ./images/filename-.jpg.

Once we have image path reference we will need to do the actual uploading using the
imageref.putString() function.
The function requires 2 parameters, which is the data of the actual picture, and the format of the data.
In the code below, since our picture was captured by the camera and stored inside the captureDataUrl, with the format of DATA_URL, we will need to tell Firebase that we will be uploading in that format:

import { Component, Input } from '@angular/core';
import { NavController, AlertController } from 'ionic-angular';
import { Camera, CameraOptions } from 'ionic-native';
import firebase from 'firebase';

@Component({
  selector: 'page-home',
  templateUrl: 'home.html'
})
export class HomePage {
  captureDataUrl: string;
  alertCtrl: AlertController;

  @Input('useURI') useURI: Boolean = true;
   
  constructor(public navCtrl: NavController,  alertCtrl: AlertController) {
     this.alertCtrl = alertCtrl;
  }


  getPicture(sourceType){
    const cameraOptions: CameraOptions = {
      quality: 50,
      destinationType: Camera.DestinationType.DATA_URL,
      encodingType: Camera.EncodingType.JPEG,
      mediaType: Camera.MediaType.PICTURE,
      sourceType: sourceType
    };

    Camera.getPicture(cameraOptions)
     .then((captureDataUrl) => {
       this.captureDataUrl = 'data:image/jpeg;base64,' + captureDataUrl;
    }, (err) => {
        console.log(err);
    });
  }  

upload() {
    let storageRef = firebase.storage().ref();
    // Create a timestamp as filename
    const filename = Math.floor(Date.now() / 1000);

    // Create a reference to 'images/todays-date.jpg'
    const imageRef = storageRef.child(`images/${filename}.jpg`);

    imageRef.putString(this.captureDataUrl, firebase.storage.StringFormat.DATA_URL)
      .then((snapshot)=> {
        // Do something here when the data is succesfully uploaded!
        this.showSuccesfulUploadAlert();
    });
  }

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

 

Add the camera provider in app.module.ts file

import { BrowserModule } from '@angular/platform-browser';
....
import { Camera } from 'ionic-native';

import { MyApp } from './app.component';
import { HomePage } from '../pages/home/home';

@NgModule({
  declarations: [
    MyApp,
    HomePage
  ],
  imports: [
    BrowserModule,
    IonicModule.forRoot(MyApp)
  ],
  bootstrap: [IonicApp],
  entryComponents: [
    MyApp,
    HomePage
  ],
  providers: [
    StatusBar,
    SplashScreen,
    {provide: ErrorHandler, useClass: IonicErrorHandler},
    Camera
  ]
})
export class AppModule {}



Ionic Camera Photo Upload in Firebase

In Ionic, we can upload a file in Firebase as easily as CRUD operation on Firebase through Ionic.  Here our app we are going to see how to take pictures on a mobile device and upload them immediately to Firebase.

What are we Learning?

  1. Uploading taken a photo of the camera to Firebase storage service.
  2. AlertController to display an alert message when we successful upload photo to Firebase Storage.

Step 1: Setting up Apps 

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

We have to create a project in firebase and click on Add Firebase to your web app. Copy the web app API from firebase project and add  in app.components.ts as highlight

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

import { HomePage } from '../pages/home/home';
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();

      const firebaseConfig = {
        apiKey: "AIUyQ",
        authDomain: "camm",
        databaseURL: "https",
        projectId: "camer",
        storageBucket: "camet.com",
        messagingSenderId: "939"
      };
      
      firebase.initializeApp(firebaseConfig);
    });
  }
}

 

Step 2: Adding user interface for Apps

Add the following code in home.ts file

<ion-header>
  <ion-navbar>
    <ion-title>Ionic Camera Firebase</ion-title>
  </ion-navbar>
</ion-header>
<ion-content padding>
  <div style="display:flex;justify-content:center">
    <button ion-button (click)="capture()">Lets take a picture!</button>
    <img [src]="captureDataUrl" *ngIf="captureDataUrl"/>
    <button ion-button (click)="upload()" *ngIf="captureDataUrl">Upload to Firebase!</button>
  </div>
</ion-content>

 

 

Step 3: Uploading pictures to Firebase

To upload photo, we will first need to get the root storage reference via firebase.storage().ref(). After that, we need to set file path in Firebase Storage. In this app, we have defined that all pictures must be inside a path ./images/filename-.jpg.

Once we have image path reference we will need to do the actual uploading using the
imageref.putString() function.
The function requires 2 parameters, which is the data of the actual picture, and the format of the data.
In the code below, since our picture was captured by the camera and stored inside the captureDataUrl, with the format of DATA_URL, we will need to tell Firebase that we will be uploading in that format:

imageRef.putString(this.captureDataUrl, firebase.storage.StringFormat.DATA_URL).then((snapshot)=> {
     // Do something here when the data is succesfully uploaded! 
});

Add the following code in home.ts file

import { Component } from '@angular/core';
import { NavController} from 'ionic-angular';
import { Camera, CameraOptions } from 'ionic-native';
import firebase from 'firebase';

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

  
  constructor(public navCtrl: NavController) {
  }

  capture() {
    const cameraOptions: CameraOptions = {
      quality: 50,
      destinationType: Camera.DestinationType.DATA_URL,
      encodingType: Camera.EncodingType.JPEG,
      mediaType: Camera.MediaType.PICTURE,
    };

    Camera.getPicture(cameraOptions)
      .then((imageData) => {
        // imageData is either a base64 encoded string or a file URI // If it's base64:
		
        this.captureDataUrl = 'data:image/jpeg;base64,' + imageData;
      }, (err) => {
      // Handle error
	  
    });
  } // End of capture camera


  upload() {
    let storageRef = firebase.storage().ref();
    // Create a timestamp as filename

    const filename = Math.floor(Date.now() / 1000);

    // Create a reference to 'images/todays-date.jpg'

    const imageRef = storageRef.child(`images/${filename}.jpg`);

    imageRef.putString(this.captureDataUrl, firebase.storage.StringFormat.DATA_URL)
      .then((snapshot)=> {
        // Do something here when the data is succesfully uploaded!


      });
  }
}

 

 

Note: As in this example, we don’t set any authentication. For access the Firebase storage we have to change to storage rule so that any one can read/write on storage. This means allowing the public to access. Click on storage rule and change the value for public access as

 

Step 4: Show prompt when upload succeeds

We are using AlertControlle component from ionic-angular package and to display alert box for successful uploading a photo to fire base.  To achieve this we have to import

import { NavController, AlertController } from ‘ionic-angular’;

add the function to show alert message
showSuccesfulUploadAlert() {
    let alert = this.alertCtrl.create({
      title: 'Uploaded!',
      subTitle: 'Picture is uploaded to Firebase',
      buttons: ['OK']
    });
    alert.present();

    // clear the previous photo data in the variable

    this.captureDataUrl = "";
  }

Adding complete code for home.ts

import { Component } from '@angular/core';
import { NavController, AlertController } from 'ionic-angular';
import { Camera, CameraOptions } from 'ionic-native';
import firebase from 'firebase';

@Component({
  selector: 'page-home',
  templateUrl: 'home.html'
})
export class HomePage {
  captureDataUrl: string;
  alertCtrl: AlertController;
  
  constructor(public navCtrl: NavController, alertCtrl: AlertController) {
    this.alertCtrl = alertCtrl;
  }

  capture() {
    const cameraOptions: CameraOptions = {
      quality: 50,
      destinationType: Camera.DestinationType.DATA_URL,
      encodingType: Camera.EncodingType.JPEG,
      mediaType: Camera.MediaType.PICTURE,
    };

    Camera.getPicture(cameraOptions)
      .then((imageData) => {
        // imageData is either a base64 encoded string or a file URI
        // If it's base64:
		
        this.captureDataUrl = 'data:image/jpeg;base64,' + imageData;
      }, (err) => {
      // Handle error
	  
    });
  } // End of capture camera


  upload() {
    let storageRef = firebase.storage().ref();
    // Create a timestamp as filename
	
    const filename = Math.floor(Date.now() / 1000);

    // Create a reference to 'images/todays-date.jpg'
	
    const imageRef = storageRef.child(`images/${filename}.jpg`);

    imageRef.putString(this.captureDataUrl, firebase.storage.StringFormat.DATA_URL)
      .then((snapshot)=> {
        // Do something here when the data is succesfully uploaded!
		
        this.showSuccesfulUploadAlert();
      });
  }

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

 

 

 

Ionic CRUD operation on Firebase through AngularFirebase 2

W e can use Firebase to store data. With Firebase we can easily do CRUD and it provides login with the different option. We are creating Ionic apps with firebase and we will be doing following as

  1. Login and register user in our app through Firebase.
  2. Register user can create and view Shopping List through CRUD on Firebase database.

Step 1:  Creating our app from blank template

We can use SDK Firebase package, but angularfire2 are easier to code in our project.

ionic start firebaseAuth blank 
npm install angularfire2 firebase --save

 

Step 2: Creating / Configuring Firebase

We need to create a project, as we have three option to select as Android, Apple and web apps. As our Ionic project, we have to select the web. Add authentication to our project, click on Authentication and select option sign in options as Email and password as 

Firebase provides a lot of authentication option as login through social network authentication eg Facebook and Google etc.  We can control the access of Firebase database inside the firebase through setting rules. If we are not using any authentication then we set all user can read/write as in

{
  "rules": {
    ".read": "true",
    ".write": "true"
  }
}

 

Step 3: Configure our app.module.ts.

Before we configure, first create a file app.firebase.config.ts file containing the Firebase API. Add the following code in app/app.firebase.config.ts

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

This information we will get from our Firebase project and add this code in app.module.ts file. Add the following code in app.module.ts file

import { BrowserModule } from '@angular/platform-browser';
....

import { MyApp } from './app.component';
import { HomePage } from '../pages/home/home';
import { RegisterPage } from '../pages/register/register';
import { LoginPage } from '../pages/login/login';
import { HttpModule } from '@angular/http';
import { AngularFireModule} from 'angularfire2';
import { AngularFireDatabaseModule} from 'angularfire2/database';
import { AngularFireAuthModule } from 'angularfire2/auth';

import { FirebaseService} from '../providers/firebase-service';
import { FIREBASE_CONFIG } from "./app.firebase.config";

@NgModule({
  declarations: [
    MyApp,
    HomePage,
    LoginPage,
    RegisterPage
  ],
  imports: [
    BrowserModule,
    HttpModule,
    AngularFireDatabaseModule,
    AngularFireModule.initializeApp(FIREBASE_CONFIG),
    IonicModule.forRoot(MyApp),
    AngularFireAuthModule
  ],
  bootstrap: [IonicApp],
  entryComponents: [
    MyApp,
    HomePage,
    LoginPage,
    RegisterPage
  ],
  providers: [
    StatusBar,
    SplashScreen,
    {provide: ErrorHandler, useClass: IonicErrorHandler},
    FirebaseService
  ]
})
export class AppModule {}

 

Step 4:  Create Firebase Service provider 

Create a Firebase service provider to access/ CRUD operation on Firebase database. First set the database rule to allow all user to read/write true. We will control the access later through creating Login/Register page

ionic g provider firebaseService

Add the following code in src/providers/firebase-service.ts

import { AngularFireDatabase } from 'angularfire2/database';
import { Injectable } from '@angular/core';

@Injectable()
export class FirebaseService {

  constructor(public afd: AngularFireDatabase) {}

  getShoppingItems(){
    return this.afd.list('/shoppingItems/');
  }

  addItems(name){
     return this.afd.list('/shoppingItems/').push(name);
  }

  removeItem(id){
     return this.afd.list('/shoppingItems/').remove(id);
  }

}

Here we are implementing CRUD operation on our Firebase database, we can easily understand the code of service.

 

Step 5: Create UI of our data on Home page

We will use the home page to display/ UI to allow the user to create/delete the shopping list. Add the following code in src/home/home.html

<ion-header>
  <ion-navbar color="primary">
    <ion-title>
      Shopping List
    </ion-title>
  </ion-navbar>
</ion-header>

<ion-content padding>
  <ion-row> 
    <ion-col col-9>
      <ion-item>
        <ion-input type="text" [(ngModel)]="newItem" placeholder="New Shopping item"></ion-input>
      </ion-item>
    </ion-col>
    <ion-col>
      <button ion-button (click)="addItem()">Add</button>
    </ion-col>
  </ion-row>

  <ion-list>
    <ion-item-sliding *ngFor="let item of shoppingItems | async">
      <ion-item>
        {{ item.$value }}
      </ion-item>
      <ion-item-options side="right">
        <button ion-button color="danger" icon-only (click)="removeItem(item.$key)">
          <ion-icon name="trash"></ion-icon>
        </button>
      </ion-item-options>
    </ion-item-sliding>
  </ion-list>
</ion-content>

We are creating FirebaseListObservable in src/home/home.ts file as

import { Component } from '@angular/core';
import { NavController, ToastController } from 'ionic-angular';
import { FirebaseService } from '../../providers/firebase-service';
import { FirebaseListObservable } from 'angularfire2/database';


@Component({
  selector: 'page-home',
  templateUrl: 'home.html'
})
export class HomePage {
  shoppingItems: FirebaseListObservable<any []>;
  newItem = '';

  constructor( public navCtrl: NavController, public firebaseService: FirebaseService){
    this.shoppingItems = this.firebaseService.getShoppingItems();
  }

  addItem(){
    this.firebaseService.addItems(this.newItem);
  }

  removeItem(id){
    this.firebaseService.removeItem(id);
  }

}

 

Step 6: Adding Login /Register in Apps

Firebase supports login and authentication internally and also provides support for integrating with social login providers. Most applications need some kind of login mechanism internally; with Firebase it’s super easy to set this up. Whenever we login using Firebase a session is created and a unique ID uid is returned by Firebase, which is distinct across all providers and never change for a specific authenticated user.

We will create two-page Login and Register page as

ionic generate page Login
ionic generate page Register

Now set the login page to root and edit root page from home to login in app.component.ts file

...
import { LoginPage } from '../pages/login/login';
..

export class MyApp {
  rootPage:any = LoginPage;
  ....
}

 

Step 7: Creating User Model

Inside src folder create a new folder called models and add the new file for user model as a src/models/user.ts. Add the following code

export interface User{
    email: string;
    password : string;
}

 

Step 8: Create UI and typescript code for Login/Register page

Add the following code in src/pages/login/login.html file

<ion-header>
  <ion-navbar>
    <ion-title>Login</ion-title>
  </ion-navbar>
</ion-header>
<ion-content padding>
  <ion-item>
    <ion-label>Email Address</ion-label>
    <ion-input type="text" [(ngModel)]="user.email"></ion-input>
  </ion-item>
  <ion-item>
    <ion-label>Password</ion-label>
    <ion-input type="password" [(ngModel)]="user.password"></ion-input>
  </ion-item>

  <button ion-button (click)="login(user)">Login</button>
  <button ion-button color="light" (click)="register()">Register</button>
</ion-content>

Add the following code in src/pages/login/login.ts file, as for login we have to create service in real apps, as for this example we will put Firebase authentication in login.ts file only.

import { Component } from '@angular/core';
import {  NavController, NavParams } from 'ionic-angular';
import { User } from '../../models/user';
import { RegisterPage } from '../register/register';
import { AngularFireAuth } from 'angularfire2/auth';
import { HomePage } from '../home/home';


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

  user = {} as User;

  constructor(private angFireAuth:AngularFireAuth, public navCtrl: NavController, public navParams: NavParams) {}

 async login(user: User){
   try{
    const result = this.angFireAuth.auth.signInWithEmailAndPassword(user.email, user.password);
    if(result){
      this.navCtrl.setRoot(HomePage);
    }
   }
   catch(e){
     console.error(e);
   }
 }

 register(){
  this.navCtrl.push(RegisterPage);
 }

}

Note : When the user passes the authentication, we will redirect the user to home page, where home page containing the shopping list. In the login page, we have two buttons one for login and one for register new user. The information of the new user will be stored in Firebase database. Clicking on Register button on login page will navigate to the regiseter page.

Add the following code in src/pages/register/register.html file 

<ion-header>
  <ion-navbar>
    <ion-title>Register</ion-title>
  </ion-navbar>
</ion-header>

<ion-content padding>
  <ion-item>
    <ion-label>Email Address</ion-label>
    <ion-input type="text" [(ngModel)]="user.email"></ion-input>
  </ion-item>
  <ion-item>
    <ion-label>Password</ion-label>
    <ion-input type="password" [(ngModel)]="user.password"></ion-input>
  </ion-item>

  <button ion-button (click)="register(user)">Register</button>
</ion-content>

Add the following code in src/pages/register/register.ts file 

import { Component } from '@angular/core';
import { NavController, NavParams } from 'ionic-angular';
import { User } from '../../models/user';
import { AngularFireAuth } from 'angularfire2/auth';
import { LoginPage } from '../login/login';

@Component({
  selector: 'page-register',
  templateUrl: 'register.html',
})
export class RegisterPage {
  user = {} as User;

  constructor(private angFireAuth: AngularFireAuth, public navCtrl: NavController, public navParams: NavParams) {
  }

  async register(user: User){
    try {
      const result = await this.angFireAuth.auth.createUserWithEmailAndPassword(user.email, user.password)
      this.navCtrl.push(LoginPage);
      console.log(result);
    }
    catch(e) {
      console.error(e);
    }
    
  }
}

In real application we have to create separate Firebase service code in service folder, for now just for example we are keeping service code with register/login page.

Step 9: Modify the home page

Once valid user login, we will redirect to home page, here we add ToastController.

Add the following code modify the code in home.ts file, we have added ToastController to display the message below on above image.

import { Component } from '@angular/core';
import { NavController, ToastController } from 'ionic-angular';
import { FirebaseService } from '../../providers/firebase-service';
import { FirebaseListObservable } from 'angularfire2/database';
import { AngularFireAuth } from 'angularfire2/auth';

@Component({
  selector: 'page-home',
  templateUrl: 'home.html'
})
export class HomePage {
  shoppingItems: FirebaseListObservable<any []>;
  newItem = '';

  constructor(private angFireAuth: AngularFireAuth,  private toast: ToastController, public navCtrl: NavController, public firebaseService: FirebaseService){
    this.shoppingItems = this.firebaseService.getShoppingItems();
  }

  addItem(){
    this.firebaseService.addItems(this.newItem);
  }

  removeItem(id){
    this.firebaseService.removeItem(id);
  }

  ionViewWillLoad(){
    this.angFireAuth.authState.subscribe(data => {
      if(data && data.email && data.uid){
        this.toast.create({
          message: `Welcome to APP_NAME', ${data.email}`,
          duration: 3000
        }).present();
      }
      else{
        this.toast.create({
          message: `Couldn't find authentication, ${data.email}`,
          duration: 3000
        }).present();
      }
    });
  }

}

Firebase – Introduction

Firebase is the product of Google. To create new Firebase projects, you need a Google account. Firebase projects can be created and managed using the Firebase console (https://firebase.google.com/console/). Firebase provides different SDKs for mobile and web apps to interact with its database. Ionic apps should use the web SDK (https://firebase. google.com/docs/web/setup).

Note: Ionic apps should use the web SDK (https://firebase. google.com/docs/web/setup).

Why Firebase?

Firebase has made the life of developers easier as they don’t have to spend time building backend server to build simple APIs. We can easily do all CRUD operations with minimum effort and with Web socket supports it’s super fast in syncing data. Also, Firebase offers offline sync, user authentication, and features or securing the data with sets of rules.

Firebase provides user authentication for multiple platforms: Custom – for integrating with existing authentication systems

  • E-mail – register and authenticate users by e-mail and password.
  • Anonymous – for guest accounts without any personal information required
  • Facebook
  • Google
  • Twitter
  • GitHub

Firebase provides many options such as Analytics, Authentication, Database, Storage, Hosting, Notification and many other options. All Firebase database data is stored as JSON objects and no relational tables exist.

 

Database Structure

Firebase has a unique database structure that is different from other databases. Each Firebase database is stored as a tree-like JSON object. This tree structure is very flexible for all kinds of data. You can organize the app’s data in a way suits most for your app. For an e-commerce app, its database can be organized as below

{
	"products": {
		"00001": {
			"name": "iPhone 6s plus",
			"price": 613.50
		},
		"00002": {
			"name": "LG Nexus 5",
			"price": 187.99
		}
	},
	"customers": {
		"00001": {
			"firstName": "Alex",
			"lastName": "Cheng",
			"email": "alex@example.com"
		}
	},
	"orders": {
		"00001": {
			"customer": "00001",
			"items": {
				"00001": true,
				"00002": true
			},
			"shippingCost": 5.00
		}
	}
}

The property products is a map of product id to its properties. The property customers is a map of customer id to its properties. The property orders is a map of order id to its properties.

Each data value in the database has a unique path to identify it. If you think of the whole JSON object as a file directory, then the path describes how to navigate from the root to a data value. For example, the path of the price of the product with id 00001 is /products/00001/price. The path /orders represent all orders. The path is used when reading or writing data, as well as configuring security rules.

 

Adding Firebase database to Ionic

We have to create new project and Google will display three platform option as Android, ISO, and the web. The Ionic is web based so we have to choose to add Firebase to the web app. Add Firebase to your web app shows a dialog with code ready to be copied into the HTML file.

Google Place id

  addPlaces(places) {
    places.forEach((place) => {
      this.db.object('/locations/' + place.place_id).valueChanges().subscribe(data => {
        place.reviewsAvg = data && data['reviewsAvg'] || 0;
        place.reviewsCount = data && data['reviewsCount'] || 0;
      });
      this.places.push(place);
    });
  }

 

    this.locationRef = db.object('/locations/' + navParams.data.place_id);
    this.location = this.locationRef.valueChanges().subscribe(data => {
      this.reviewsAvg = data && data.reviewsAvg || 0;
      this.reviewsCount = data && data.reviewsCount || 0;
    });
    thi

 

 profileRef = {} as ProfileRef;  

this.db.object('/profiles/' + this.navParams.get('userId')).valueChanges().subscribe(data => {
      console.log("profile data : ", data);
      this.profileRef = <ProfileRef> data;
      
    },
    err => console.log("error in retrieving user from profile : "+err),
    () => console.log("user profile key retrieve successful"));

 

Taking review From single user 

this.reviews = db.list('/reviews', ref => 
  
 ref.orderByChild('uid').equalTo(navParams.data.userId)).valueChanges();

Ionic with Firebase for Hacker News Apps

To describe the app’s requirements, we list the main user stories as below.

  1. View top stories – Users can view a list of top stories on Hacker News and view the page of each story.
  2. View comments – For each story, users can view its comments. For each comment, users can also view replies to that comment.
  3. Add stories to favorites – Users can add a story to favorites and see a list of all favorite stories.
  4. Share stories – Users can share stories to the social network.
ionic start hacker_news_app sidemenu

$ ionic platform add ios --save
$ ionic platform add android --save

 

Step 1: Listing the Stories

We start implementing the first user story that lists Hacker News top stories. We are going to cover the following topics in this long chapter. Use the list component to show top stories and test with Jasmine and Karma. Services to load top stories.

  1. Firebase basics and Hacker News API.
  2. Infinite scrolling and pull-to-refresh.
  3. Loading indicators and error handling.

Define the Model
The app starts, the user is presented with a list of top stories on Hacker News. The user can see basic information on each story on the list, including title, URL, author, published time, and score. The information for each story should be declared in the model.

A model in programming is a generic concept, and you may have come across it with common patterns like Model-View-Controller (or MVC). Depending on the context, the exact definition of a model may vary, but in general, a model is used to store or represent data.
We declare the model as a TypeScript interface in. Here we use a more general model name Item instead of Story because comments are also items and can share the same model.

export interface Item {
	id: number;
	title: string;
	url: string;
	by: string;
	time: number;
	score: number;
}

The list of top stories can be represented as an array of items, that is, Item[]. However, we define a type Items in below to represent a list of items.

import { Item } from './Item';
export type Items = Item[];

In app we will create the folder called app/model/ and add two files as item.ts and items.ts file. Add the following code in item.ts file

export interface Item {
  id: number;
  title: string;
  url: string;
  by: string;
  time: number;
  score: number;
  text?: string;
  descendants?: number;
  kids?: number[];
  isFavorite?: boolean;
}

And add the following code in items.ts

import { Observable } from 'rxjs';
import { Item } from './Item';

export interface Items {
  refresh?: boolean;
  offset: number;
  limit: number;
  total?: number;
  results: Observable<Item>[];
  loading?: boolean;
}

 

Step 2: Display a List of Items through component

After defining the model Item and learning the component ion-list, we are now ready to display a list of items in the app. We need to create a component for the list of items and another component for each item in the list.

$ ionic g component Items
$ ionic g component Item

Ionic CLI creates the necessary files for a component, including TypeScript file, HTML template file, and Sass file. For the generated component, these files are created under the related subdirectory of the src/components directory.

Add or modify the app/components/item/item.ts file. 

import { Component, Input } from '@angular/core';
import { Item } from '../../model/item';

@Component({
  selector: 'item',
  templateUrl: 'item.html'
})
export class ItemComponent {
  @Input() item: Item;
}

Add or modify the app/components/item/item.html file. 

<div>
  <h2 class="title">{{ item.title }}</h2>
  <div> 
    <span><ion-icon name="bulb"></ion-icon>{{ item.score }}</span>
    <span>
      <ion-icon name="person"></ion-icon>
      {{ item.by }}
    </span>
    <span>
      <ion-icon name="time"></ion-icon>
      {{ item.time | timeAgo }}
    </span>
  </div>
  <div>
    <span>
      <ion-icon name="link"></ion-icon>
      {{ item.url }}
    </span>
  </div>
</div>

Important: The timeAgo used in {{ item.time | timeAgo }} is an Angular 2 pipe to transform the timestamp item.time into a human-readable text, like 1 minute ago or 5 hours ago. The implementation of TimeAgoPipe uses the taijinlee/humanize (https://github.com/taijinlee/humanize) library to generate a human-readable text. So we need to install the humanize library to our projects as

ionic generate pipe TimeAgoPipe
npm install humanize --save

Some example of humanize used, 

humanize.date('Y-m-d'); // 'yyyy-mm-dd'
humanize.filesize(1234567890); // '1.15 Gb'

Add/Modify the following code in src/app/pipes/time-ago-pipe.ts 

import { Pipe, PipeTransform } from '@angular/core';
import * as humanize from 'humanize';

@Pipe({
  name: 'timeAgo',
})
export class TimeAgoPipe implements PipeTransform {
  
  transform(time: number) {
    return humanize.relativeTime(time);
  }
}

 

Items Component

The ItemsComponent is used to render a list of items. Add the following code in src/components/items/items.ts, the selector for this component is items. It also has the property items that are bound to the value of the property items from its parent component.

import { Component, Input } from '@angular/core';
import { Items } from '../../model/Items';

@Component({
  selector: 'items',
  templateUrl: 'items.html',
})
export class ItemsComponent {
  @Input() items: Items;
}

 

Add or modify the app/components/item/items.html file. 

<ion-list *ngIf="items.length > 0">
  <ion-item *ngFor="let item of items">
    <item [item]="item"></item>
  </ion-item>
</ion-list>
<p *ngIf="items.length === 0">
  No items.
</p>

 

Step 3: Items Loading Service:

In Angular apps, code logic that deals with external resources should be encapsulated in services.
ItemService in below has a single method load(offset, limit) to load a list of items. Because there can be many items, the load() method only loads a subset of items. Parameters offset and limit are used for pagination: offset specifies the position of the first loaded item in the whole items list, limit specifies the number of loaded items. For example, load(0, 10) means loading the first 10 items. Add the following code in src/providers/ItemService.ts

import { Injectable } from '@angular/core';
import { Observable } from 'rxjs';
import { Items } from '../model/Items';

@Injectable()
export class ItemService {
  load(offset: number, limit: number): Observable<Items> {
    return Observable.of({
      offset: 0,
      limit: 0,
      total: 0,
      results: [],
    });
  }
}

ItemService uses decorator factory Injectable, so it’ll be registered to Angular 2’s injector and available for dependency injection to other components

The return type of the load() method is Observable<Items>. Items are the model type we defined already and now we have to update the Items model to add more information related to pagination. The Items type now has both offset and limit properties that match the parameters in the load() method. It also has the property total that represents the total number of items. The property total is optional, because in some cases the total number may not be available. The property results represent the actual array of items.

Updated Item model 

import { Observable } from 'rxjs';
import { Item } from './Item';

export interface Items {
  refresh?: boolean;
  offset: number;
  limit: number;
  total?: number;
  results: Observable<Item>[];
  loading?: boolean;
}

Step 4: Adding the page – Top Stories Page 
Now we can create a new page in the Ionic app to show top stories using ItemsComponent and ItemService. TopStoriesPage class has property items of type Items. The value of this property is passed to the ItemsComponent for rendering.

ionic g page topStories

Add the following line of code in src/pages/top-stories/top-stories.ts file

import { Component, OnInit, OnDestroy } from '@angular/core';
import { NavController } from 'ionic-angular';
import { Subscription } from "rxjs";
import { Items } from '../../model/Items';
import { ItemService } from '../../providers/ItemService';

@Component({
selector: 'page-top-stories',
templateUrl: 'top-stories.html'
})
export class TopStoriesPage implements OnInit, OnDestroy {
  items: Items;
  subscription: Subscription;
  constructor(public navCtrl: NavController, private itemService: ItemService) {}
  
  ngOnInit(): void {
    this.subscription = this.itemService.load(0, 10).subscribe(items =>
      this.items = items
    );
  }

  ngOnDestroy(): void {
    if (this.subscription) {
      this.subscription.unsubscribe();
    }
  }
}

In the ngOnInit() method, the method load() of ItemService is invoked. When the loading is finished, loaded items is set as the value of the property items. TopStoriesPage class also implements the OnDestroy interface. In the method ngOnDestroy(), we use the method unsubscribe() of the Observable subscription to make sure resources are released.

 

Add the following line of code in src/pages/top-stories/top-stories.html file

<ion-header>
  <ion-navbar>
    <button ion-button menuToggle>
      <ion-icon name="menu"></ion-icon>
    </button>
    <ion-title>Top Stories</ion-title>
  </ion-navbar>
</ion-header>
<ion-content padding>
  <items *ngIf="items" [items]="items"></items>
</ion-content>

Important: In above highlight code <items *ngIf=”items” [items]=”items”></items> creates the ItemsComponent and binds the value of the property items to the items in TopStoriesPage class. Because loading items are asynchronous, the value of items is null until the loading is finished successfully. The usage of directive ngIf is to make sure the ItemsComponent is only created after items are loaded.

Step 5: Creating Database – Firebase

npm install angularfire2 --save