Crud ionic 3 con firebase

Firebase database es un servicio de la plataforma firebase que nos permite sincronizar y almacenar los datos de nuestra aplicación en su base de datos NoSql. La combinación de Ionic con Firebase se utiliza mucho, ya que la plataforma firebase nos ofrece un marco backend muy sencillo, potente y con una muy buena documentación.

Alguno de los pros de firebase es que su base de datos es real time, cuenta con un backend listo para ser usado y además se puede trabajar sin conexión a internet, lo que da una muy buena experiencia de usuario a nuestra aplicación.

Configurar Firebase para Ionic

Para comenzar, debemos ir a la plataforma de firebase y daremos click a la opción comenzar, que nos llevará a la siguiente ventana, donde daremos click a agregar proyecto:

Una vez hemos rellenado la información de nuestro proyecto, nos llevará al panel de control de firebase donde debemos darle click a esta opción:

Debemos estar atentos a este código, ya que más adelante debemos hacer uso de él. Solo necesitaremos esta parte:

var config = {
    apiKey: "AIzaSyBNvhDmemnmCVlR1pWxUer7RCOH0keIaBY",
    authDomain: "gestor-64037.firebaseapp.com",
    databaseURL: "https://gestor-64037.firebaseio.com",
    projectId: "gestor-64037",
    storageBucket: "gestor-64037.appspot.com",
    messagingSenderId: "369296883446"
  };

Una vez tengamos guardado nuestro código, nos dirigimos a la sidebar de la izquierda y seleccionaremos «desarrollo».

Dentro buscaremos el apartado Realtime database y daremos click en crear base de datos:

En la nueva ventana selecionaremos la opción «empezar con el modo de pruebas»:

Una vez dentro, arriba debemos tener seleccionada esta opción:

Una vez hecho esto, ya tenemos nuestra base de datos lista para conectar con nuestra aplicación ionic.

Instalar firebase en Ionic

Ahora vamos a comenzar con la instalación de firebase en nuestra aplicación, para poder conectarnos con la plataforma firebase database.

Debemos instalar estas dos librerias mediante npm en nuestra consola:

npm install angularfire2@5.0.0-rc.9

npm i rxjs@^6.0 rxjs-compat

Cuando hayamos terminado de instalar estas dos librerías, vamos a crear el servicio que será el responsable de hacer las consultas a la base de datos. Crearemos la carpeta services en el directorio src y dentro de ella crearemos el servicio fruits.service.ts:

que de momento, dejaremos así:

import {Injectable} from '@angular/core';
import { AngularFireDatabase } from '@angular/fire/database';
import { Observable } from 'rxjs-compat';

@Injectable()
export class FruitsService{

    constructor(){

    }

}

Ahora nos dirigimos a nuestro app.module.ts, donde añadiremos nuestro nuevo servicio y el código que hemos copiamos antes en el panel de control de firebase, que añadiremos en la constante firebaseConfig como aparece aquí:

...
...

import {FruitsService} from '../services/fruits.service';

import { AngularFireModule } from '@angular/fire';
import { AngularFireDatabaseModule, AngularFireDatabase } from '@angular/fire/database';
import { AngularFireAuthModule } from '@angular/fire/auth';

export const firebaseConfig = {
  apiKey: "AIzaSyBNvhDmemnmCVlR1pWxUer7RCOH0keIaBY",
    authDomain: "gestor-64037.firebaseapp.com",
    databaseURL: "https://gestor-64037.firebaseio.com",
    storageBucket: "gestor-64037.appspot.com",
    messagingSenderId: "369296883446"
};

@NgModule({
  declarations: [
    MyApp,
    HomePage
  ],
  imports: [
    ...
    ...
    AngularFireModule.initializeApp(firebaseConfig),
    AngularFireDatabaseModule,
    AngularFireAuthModule
  ],
  bootstrap: [IonicApp],
  entryComponents: [
    MyApp,
    HomePage
  ],
  providers: [
    ...
    FruitsService,
    AngularFireDatabase,
  ]
})
export class AppModule {}

Configuración de nuestro servicio firebase

Vamos a crear en nuestro servicio fruits.service.ts las funciones que guardaran, modificaran, borrarán y listaran las frutas que tengamos en nuestra base de datos:

import {Injectable} from '@angular/core';
import { AngularFireDatabase } from '@angular/fire/database';
import { Observable } from 'rxjs-compat';

@Injectable()
export class FruitsService{

    constructor(public afDB: AngularFireDatabase){

    }

    public getFruits(){
        return this.afDB.list('fruits/').valueChanges(); 
        //Esta función devolverá todos los datos que tengamos en el apartado fruits, en nuestra base de datos
    }
    public saveFruit(fruit){
        let key = this.afDB.list('/fruits/').push(fruit).key;
        //Guardamos la fruta y obetenemos el id que firebase pone al nudulo de nuestra fruta.
        //Al guardarse sin id nuestra fruta, ahora la actualizamos con el id que firebase nos devuelve.
        fruit.id = key;
        this.afDB.database.ref('fruits/'+fruit.id).set(fruit);

    }
    public updateFruit(fruit){
        //Actualizamos la fruta con el id que recibimos del objeto del parametro
        this.afDB.database.ref('fruits/'+fruit.id).set(fruit);
    }
    public getFruit(id){
        return this.afDB.object('fruits/'+id).valueChanges();
        //Devolvera la fruta con el id que le pasamos por parametro
    }
    public removeFruit(id){
        this.afDB.database.ref('fruits/'+id).remove();
        //Borrará la fruta con el id que le pasamos por parametro
    }

}

Configuración de nuestro home.ts

Ahora nos dirijimos a la page donde vamos a mostrar estos datos, en mi caso, la mostraré en home.

En mi home.ts crearé lo siguiente:

import { Component } from '@angular/core';
import { NavController } from 'ionic-angular';
import {FruitsService} from '../../services/fruits.service';

@Component({
  selector: 'page-home',
  templateUrl: 'home.html'
})
export class HomePage {
  idSelected:any; //Esta variable se cargará cuando elijamos una fruta, así controlamos si es una fruta nueva o para actualizar
  show:boolean; //Esta variable contralará cuando queremos que se muestren los campos para introducir o actualizar una fruta
  fruits = []; //Array donde cargaremos las frutas que hay en la base de datos y las mostraremos en nuestra page
  fruit = {id:0, name:null, quantity:null}; //Declaramos un objeto vacio de fruta

  constructor(public navCtrl: NavController, public fruitsService:FruitsService) {
    this.show = false; //Inicializamos la variable a false, para que por defecto no se muestren los campos
    this.idSelected = 0; // Inicializamos a 0 idselected, que significará que no tenemos ninguna fruta existente selecionada.

    fruitsService.getFruits()
      .subscribe(fruits->{
        this.fruits = fruits;
      });//Hacemos una llamada a nuestro servicio, al metodo getFruits y nos devolvera toda la fruta que hay en nuestr abase de datos
        // y las cargaremos en nuestro array
  }

  saveFruit(){
    if(this.idSelected != 0){//si es diferente a 0 actualizamos, sino creamos uno nuevo
      this.fruitsService.updateFruit(this.fruit);
    }else{
      this.fruitsService.saveFruit(this.fruit);
    }
    this.clear();
  }
  selectFruit(id){ //selecionamos una fruta y mostramos los campos
    this.show = true;
    this.idSelected = id;//cogemos su id

    let receivedFruit:any; //declaramos un objeto vacio que será el que reciba la información de la fruta que seleccionamos

    this.fruitsService.getFruit(id)//hacemos uso de la funcion getfruit de nuestro servicio
    .subscribe(fruit->{
      receivedFruit = fruit;//el objeto vacio recibe la variable
      this.fruit = receivedFruit;//Y se lo asignamos al objeto fruta los valores que se han retornado del servicio
    });
  }
  removeSelectedFruit(){
    //Llamamos a la funcion removeFruit de nuestro servicio, le pasamos el idselected y se borra esa fruta
    this.fruitsService.removeFruit(this.idSelected);
    this.clear();
  }
  clear(){
    //inicializamos los valores de las variables una vez hecha una acción
    this.show = false;
    this.idSelected = 0;
    this.fruit.name = null;
    this.fruit.id = null;
    this.fruit.quantity  = null;
  }

}

Configuración de nuestro home.html

<ion-header>
  <ion-navbar>
    <ion-title>
      Gestor de frutas
    </ion-title>
  </ion-navbar>
</ion-header>

<ion-content>
  <div padding *ngIf="show"><!--Comprobamos si la variable show esta en true, si es asi se muestran los campos-->
      <ion-item>
        <ion-label floating>Nombre</ion-label>
        <ion-input type="text" [(ngModel)]="fruit.name"></ion-input> <!--Mediante el atributo ngModel, este campo tendrá el valor del name de la fruta-->
      </ion-item>
      <ion-item>
        <ion-label floating>Cantidad</ion-label>
        <ion-input type="text" [(ngModel)]="fruit.quantity"></ion-input><!--Mediante el atributo ngModel, este campo tendrá el valor del quantity de la fruta-->
      </ion-item>
        <button (click)="saveFruit()" ion-button full>Guardar</button><!--Mediante el atributo click, llamará a nuestra funcion de guardar fruta en home.ts-->
        <button *ngIf="idSelected != 0" (click)="removeSelectedFruit()" ion-button full color="danger">Borrar</button>
        <!--Solo aparecerá si idSelected es diferente a 0, Mediante el atributo click, llamará a nuestra funcion de remove fruta en home.ts-->
  </div>
    <ion-list>
      <button ion-item *ngFor="let fruit of fruits" (click)="selectFruit(fruit.id)"><!--Recorremos el array fruits que hemos cargado en el constructor home.ts-->
        Nombre: {{ fruit.name }} | Unidades: {{fruit.quantity}} <!--Mostramos el nombre y la cantidad-->
      </button>  
    </ion-list>
  <ion-fab bottom right>
      <button (click)="show = !show" ion-fab mini><ion-icon name="add"></ion-icon></button><!--Con este botón mostramos u ocultamos los campos-->
    </ion-fab>
</ion-content>

Una vez hecho esto, ejecutamos nuestra aplicación ionic con:

ionic serve

Y este sería nuestro resultado: