Tutorial de Ionic – Firebase – parte 2: Database – Guardar nuestros sitios en la nube.

En el siguiente enlace tienes el 铆ndice para acceder al resto de entradas de este tutorial:

 

隆隆Atenci贸n!! este tutorial se basa en ionic 3 y est谩 desactualizado por lo que es posible que los ejemplos no funcionen en la 煤ltima versi贸n de ionic, haz click aqu铆 para acceder a un tutorial mas actual de Ionic.

Hola a todos:

El el post anterior vimos como autenticar un usuario en firebase con email y contrase帽a, hoy vamos ha ver como utilizar Firebase Database para guardar nuestros sitios en la nube.

Para ello vamos a crear un provider para gestionar nuestros sitios en firebase Database, por lo tanto desde consola nos situamos dentro de la carpeta de nuestro proyecto y creamos en nuevo provider:

ionic g provider firebaseDb

Ahora editamos el archivo firebase-db.ts que se acaba de generar dentro de la carpeta providers/firebase-db, eliminamos el import Http y rxjs/add/operator/map e importamos AngularFireDatabase,FirebaseListObservable 聽y nuestro provider AuthProvider聽quedando de la siguiente manera:

import { Injectable } from '@angular/core';
import { AngularFireDatabase, AngularFireList } from 'angularfire2/database';
import { AuthProvider } from '..auth/auth';
/*
聽聽Generated class for the FirebaseDbProvider provider.

聽聽See https://angular.io/docs/ts/latest/guide/dependency-injection.html
聽聽for more info on providers and Angular DI.
*/
@Injectable()
export class FirebaseDbProvider {

  constructor(public afDB: AngularFireDatabase, public auth: AuthProvider) {
    console.log('Hello FirebaseDbProvider Provider');
  }
}

Como necesitamos el id del usuario lo primero que vamos ha hacer es a帽adir la funci贸n getUser al provider auth que creamos en el post anterior, por lo tanto editamos auth.ts y a帽adimos esta funci贸n:

// Obtenemos el id de usuario.
 getUser(){
    return this.afAuth.auth.currentUser.uid;
 }

Bien, ahora que ya podemos obtener el id de usuario vamos a a帽adir en el archivo聽firebase-db.ts聽un m茅todo para guardar nuestros sitios en Firebase database:

guardaSitio(sitio){
     sitio.id  = Date.now();
     return this.afDB.database.ref('sitios/'+this.auth.getUser()+'/'+sitio.id).set(sitio)
  }

Como vemos la funci贸n recibe como par谩metros 聽sitio que ser谩 un objeto con los datos de nuestro sitio.

Al objeto sitio le a帽adimos un campo id para identificarlo y as铆 poder luego modificarlo. Como necesitamos que el id sea diferente cada vez vamos a utilizar Date.now() que nos devuelve los milisegundos transcurridos desde el 1 de enero de 1970, con esto 聽nos aseguramos que no se repita el id, a no ser que seas capaz de guardar dos sitios en menos de un milisegundo ;-P.

En firebase se guarda la informaci贸n con estructura de 谩rbol en formato JSON. Para acceder a ella tenemos que hacer referencia a la “ruta” a la que queremos acceder.

En este caso le estamos diciendo que guarde nuestro sitio con esta estructura ‘sitio/_id_usuari_/_id_sitio_/_sitio_’.

El id de usuario lo obtenemos con la funci贸n que acabamos de definir en 聽AuthProvide 聽this.auth.getUser().

Dentro de sitio colgar谩n los diferentes id de usuarios de los cuales a su vez colgar谩n los diferentes sitios de cada usuarios.

Para verlo mas claro en el modal nuevo-sitio vamos a modificar el m茅todo guardarSitio聽para que en lugar de guardar el sitio en la base de datos local SQlite lo guarde en firebase y podamos ver la estructura de como se guarda la informaci贸n en firebase.

Editamos聽modal-nuevo-sitio.ts y hacemos los siguientes cambios:

import { Component } from '@angular/core';
import { IonicPage, NavController, NavParams, ViewController  } from 'ionic-angular';
import { Camera, CameraOptions } from '@ionic-native/camera';
// import { DbProvider } from '../../providers/db/db';
import { FirebaseDbProvider } from '../../providers/firebase-db/firebase-db';


/**
聽* Generated class for the ModalNuevoSitioPage page.
聽*
聽* See http://ionicframework.com/docs/components/#navigation for more info
聽* on Ionic pages and navigation.
*/

@IonicPage()
@Component({
  selector: 'page-modal-nuevo-sitio',
  templateUrl: 'modal-nuevo-sitio.html',
})
export class ModalNuevoSitioPage {

  coords : any = { lat: 0, lng: 0 }
  address: string;
  description: string = '';
  foto: any = '';

  constructor(
    public navCtrl: NavController,
    public navParams: NavParams,
    private viewCtrl : ViewController,
    private camera: Camera,
    // private db: DbProvider
    private dbFirebase :FirebaseDbProvider,
  ) {

  }

  ionViewDidLoad() {
    console.log('ionViewDidLoad ModalNuevoSitioPage');
      this.coords.lat = this.navParams.get('lat');
      this.coords.lng = this.navParams.get('lng');
       this.getAddress(this.coords).then(results=> {
        this.address = results[0]['formatted_address'];
      }, errStatus => {
          // Aqu铆 ir铆a el c贸digo para manejar el error
      });
  }

  cerrarModal(){
    this.viewCtrl.dismiss();
  }

  getAddress(coords):any {
    var geocoder = new google.maps.Geocoder();

    return new Promise(function(resolve, reject) {
        geocoder.geocode({'location': coords} , function (results, status) { // llamado asincronamente
            if (status == google.maps.GeocoderStatus.OK) {
                resolve(results);
            } else {
                reject(status);
            }
        });
    });
  }

  sacarFoto(){

    let cameraOptions : CameraOptions = {
聽聽聽聽聽聽聽聽quality: 50,
聽聽聽聽聽聽聽聽encodingType: this.camera.EncodingType.JPEG,
聽聽聽聽聽聽聽聽targetWidth: 800,
聽聽聽聽聽聽聽聽targetHeight: 600,
聽聽聽聽聽聽聽聽destinationType: this.camera.DestinationType.DATA_URL,
聽聽聽聽聽聽聽聽sourceType: this.camera.PictureSourceType.CAMERA,
聽聽聽聽聽聽聽聽correctOrientation: true
    }


    this.camera.getPicture(cameraOptions).then((imageData) => {
      // imageData is a base64 encoded string
        this.foto = "data:image/jpeg;base64," + imageData;
    }, (err) => {
        console.log(err);
    });
  }

  guardarSitio(){
    let sitio = {
聽聽聽聽聽聽lat: this.coords.lat,
聽聽聽聽聽聽lng: this.coords.lng ,
聽聽聽聽聽聽address: this.address,
聽聽聽聽聽聽description: this.description,
聽聽聽聽聽聽foto: this.foto
    }
  
this.dbFirebase.guardaSitio(sitio).then(res=>{
        console.log('Sitio guardado en firebase:');
        this.cerrarModal();
    })
   }
}

Como ahora vamos a guardar nuestros sitios en firebase he comentado el import de DbProvider ya que ahora no lo vamos a utilizar, y en la funci贸n guardarSitio hemos sustituido la linea this.db.addSitio… por聽this.dbFirebase.guardaSitio…

Como vemos llamamos a la funci贸n guardaSitio del provider聽FirebaseDbProvider聽que hemos creado m谩s arriba y le pasamos como par谩metro el objeto sitio con los datos de nuestro sitio.

Ahora ejecutamos nuestra aplicaci贸n y vamos a la consola de firebase, antes de guardar ning煤n sitio si seleccionamos Database en el men煤 de la izquierda de la consola de firebase veremos algo como esto:

Ahora vamos a guardar un nuevo sitio desde nuestra app, rellenamos los campos del formulario del modal nuevo sitio y le damos a guardar, si todo ha ido bien ahora en la consola de firebase veremos algo como esto (pulsa en el icono ‘+’ para desplegar los campos):

Como vemos los datos de guardan en una estructura de 谩rbol, en el primer nivel esta sitio, de sitio ‘cuelga’ los id de usuario, en este caso solo tenemos el nuestro pero si distribu铆s la aplicaci贸n por cada usuario habr谩 un nodo, de cada usuario ‘cuelgan’ los ids de cada sitio, y de cada id a su vez cuelgan los campos del sitio.

Ahora que ya podemos guardar nuestros sitios en firebase vamos a ver como podemos obtener todos los sitios que tenemos guardados para mostrarlos en el listado:

Lo primero que vamos ha hacer es crear una funci贸n en firebase-db.ts聽para obtener el listado de sitios guardados en firebase database:

getSitios(){
    return this.afDB.list('sitios/'+this.auth.getUser()).valueChanges();
  }

Para obtener el listado de sitios guardados utilizamos el m茅todo list聽de AngularFireDatabase pasando como par谩metro la ruta a partir de la cual queremos obtener los datos, en este caso queremos obtener todo lo que cuelgue de sitios/id_usuario, 聽es decir todos los sitios de nuestro usuario, el id de usuario una vez m谩s lo obtenemos con this.auth.getUser()聽que hemos creado en nuestro provider AuthProvider.

Con聽.valueChanges()聽devolvemos un observable cuando se produzcan cambios en la base de datos.

Bien, llegados a este punto vamos a modificar el controlador de la p谩gina listado para que en lugar de obtener los datos de la base de datos local los obtenga directamente de firebase.

Editamos listado.ts聽e importamos FirebaseDbProvider:

import { Component } from '@angular/core';
import { AlertController, IonicPage, NavController, NavParams, ModalController } from 'ionic-angular';
import { DbProvider } from '../../providers/db/db';
import { FirebaseDbProvider } from '../../providers/firebase-db/firebase-db';


/**
聽* Generated class for the ListadoPage page.
聽*
聽* See http://ionicframework.com/docs/components/#navigation for more info
聽* on Ionic pages and navigation.
*/

@IonicPage()
@Component({
  selector: 'page-listado',
  templateUrl: 'listado.html',
})
export class ListadoPage {

  sitios: any;

  constructor(
    public navCtrl: NavController,
    public navParams: NavParams,
    public db : DbProvider,
    public modalCtrl : ModalController,
    public alertCtrl : AlertController,
    public dbFirebase :FirebaseDbProvider,

  ) {

  }

Ahora en la funci贸n ionViewDidEnter()聽vamos a sustituir this.db.getSitios().then((res)=>{…})聽por lo siguiente:

ionViewDidEnter(){
   
    this.dbFirebase.getSitios().subscribe(sitios=>{
      this.sitios = sitios;
    })

}

La funci贸n getSitios() que como hemos visto a su vez llama al m茅todo list de AngularFireDatabase nos devuelve un observable, por lo que nos suscribimos al resultado. Aqu铆 podemos ver claramente la diferencia entre un observable y una promesa.

Guardamos en this.sitios la lista de sitios que obtenemos lo que har谩 que se refresque autom谩ticamente en la vista del listado.

Como ya sabemos una promesa ejecuta lo que tengamos definido en 聽then(res=>{ …}) una vez tenga listo el resultado, pero esto se ejecuta una 煤nica vez, sin embargo un observable va a ejecutar lo que tengamos definido en .subscribe(res=>{…})聽cada vez que haya un cambio en el resultado. Por ejemplo si desde la consola de firebase cambiamos a mano el campo description de nuestro sitio, este se ver谩 autom谩ticamente reflejado en nuestra aplicaci贸n, es interesante hacer la prueba.

En este momento ya podemos guardar sitios en firebase y mostrarlos en el listado:

Lo siguiente que vamos ha hacer es la modificaci贸n de los sitios guardados.

Para ello primero vamos ha hacer una peque帽a modificaci贸n a la funci贸n guardaSitio() de nuestro provider firebase-db.ts:

guardaSitio(sitio){
   if(!sitio.id){
      sitio.id  = Date.now();
    }
    return this.afDB.database.ref('sitios/'+this.auth.getUser()+'/'+sitio.id).set(sitio)
  }

Hemos a帽adido un if para comprobar si el sitio que recibimos en la funci贸n tiene el campo id definido.

Como utilizamos el id del sitio para establecer la ruta del registro, si el sitio que recibimos para guardar no tiene id significa que es un sitio nuevo y entonces le damos un id, si ya tiene un id significa que es un sitio que ya existe y hay que modificar.

Modificar un registro en firebase se hace exactamente igual que crear uno nuevo, si la ruta a la que hacemos referencia no existe crea el registro, si ya existe entonces modifica el registro existente en firebase.

Ahora vamos a 聽modificar el archivo modal-detalle-sitio.ts聽para hacer que al guardar los cambios al editar un sitio existente se guarden los cambios en firebase, para ello vamos a importar FirebaseDbProvider para poder llamar a la funci贸n guardaSitio que acabamos de modificar, y vamos tambi茅n a modificar la funci贸n guardarCambios聽para que guarde los cambios en firebase en lugar de en la base de datos local:

import { Component } from '@angular/core';
import { IonicPage, NavController, NavParams, ViewController } from 'ionic-angular';
import { LaunchNavigator } from '@ionic-native/launch-navigator';
import { Camera, CameraOptions } from '@ionic-native/camera';
// import { DbProvider } from '../../providers/db/db';
import { FirebaseDbProvider } from '../../providers/firebase-db/firebase-db';

/**
聽* Generated class for the ModalDetalleSitioPage page.
聽*
聽* See http://ionicframework.com/docs/components/#navigation for more info
聽* on Ionic pages and navigation.
*/

@IonicPage()
@Component({
  selector: 'page-modal-detalle-sitio',
  templateUrl: 'modal-detalle-sitio.html',
})
export class ModalDetalleSitioPage {

  sitio: any;
  edit : boolean = false;

  constructor(
    public navCtrl: NavController,
    public navParams: NavParams,
    private viewCtrl : ViewController,
    private launchNavigator : LaunchNavigator,
    private camera: Camera,
  //  private db: DbProvider,
    private dbFirebase :FirebaseDbProvider

  ) {
     this.sitio = this.navParams.data;
  }

  ionViewDidLoad() {
    console.log('ionViewDidLoad ModalDetalleSitioPage');
  }

  cerrarModal(){
    this.viewCtrl.dismiss();
  }

  comoLlegar(){
    let destino = this.sitio.lat+', '+this.sitio.lng;
    this.launchNavigator.navigate(destino)
    .then(
      success => console.log('Launched navigator'),
      error => console.log('Error launching navigator', error)
    );
 }

 editar(){
   this.edit = true;
 }

 sacarFoto(){

    let cameraOptions : CameraOptions = {
聽聽聽聽聽聽聽聽quality: 50,
聽聽聽聽聽聽聽聽encodingType: this.camera.EncodingType.JPEG,
聽聽聽聽聽聽聽聽targetWidth: 800,
聽聽聽聽聽聽聽聽targetHeight: 600,
聽聽聽聽聽聽聽聽destinationType: this.camera.DestinationType.DATA_URL,
聽聽聽聽聽聽聽聽sourceType: this.camera.PictureSourceType.CAMERA,
聽聽聽聽聽聽聽聽correctOrientation: true
    }


    this.camera.getPicture(cameraOptions).then((imageData) => {
      // imageData is a base64 encoded string
        this.sitio.foto = "data:image/jpeg;base64," + imageData;
    }, (err) => {
        console.log(err);
    });
  }

  guardarCambios(){

     let sitio = {
      id : this.sitio.id,
聽聽聽聽聽聽lat: this.sitio.lat,
聽聽聽聽聽聽lng: this.sitio.lng ,
聽聽聽聽聽聽address: this.sitio.address,
聽聽聽聽聽聽description: this.sitio.description,
聽聽聽聽聽聽foto: this.sitio.foto
    }

    this.dbFirebase.guardaSitio(sitio).then(res=>{
        console.log('Sitio modificado en firebase');
        this.cerrarModal();
    })
   }

}

Hemos comentado el import de聽DbProvider porque ya no lo estamos utilizando.

Ahora si pruebas la aplicaci贸n con el panel de firebase abierto podr谩s ver que si modificas un sitio que tengas guardado autom谩ticamente se ver谩 reflejado este cambio en el registro de firebase.

Para concluir solo nos queda eliminar sitios.

Vamos a a帽adir a 聽FirebaseDbProvider en el聽archivo firebase-db.ts聽una funci贸n para eliminar un sitio de la base de datos de firebase:

public borrarSitio(id){
        this.afDB.database.ref('sitios/'+this.auth.getUser()+'/'+id).remove();

}

Como puedes ver es muy sencillo, solo necesitamos recibir el id del sitio que queremos eliminar y haciendo referencia a la ruta de nuestro sitio (que una vez m谩s es sitios/_id_usuario_/id_sitio) utilizamos la funci贸n remove() para eliminar el sitio.

Ahora en el listado solo tenemos que sustituir la llamada a borrarSitio()聽de la base de datos local聽聽de聽DbProvider聽por la funci贸n que acabamos de crear en聽FirebaseDbProvider, por lo tanto editamos el archivo listado.ts聽y dejamos la funci贸n borrarSitio() de la siguiente manera:

borrarSitio(id){

    let alert = this.alertCtrl.create({
      title: 'Confirmar borrado',
      message: '驴Est谩s seguro de que deseas eliminar este sitio?',
      buttons: [
        {
          text: 'No',
          role: 'cancel',
          handler: () => {
            // Ha respondido que no as铆 que no hacemos nada
          }
        },
        {
          text: 'Si',
          handler: () => {
               // Aqu脥 borramos el sitio en firebase
              this.dbFirebase.borrarSitio(id);
           }
        }
      ]
    });

    alert.present();

 }

Como podemos observar ya no necesitamos obtener de nuevo los sitios una vez borrado para que se refresque el listado ya que al ser firebase una base de datos en tiempo real el listado se actualiza autom谩ticamente.

Pod茅is probar a borrar un sitio y ver茅is como el sitio se elimina autom谩ticamente en el panel de firebase y el listado se actualiza.

Eso es todo por hoy, con esto ya podemos hacer muchas cosas interesantes utilizando firebase, seguro que se os ocurren grandes ideas para realizar apps utilizando firebase como backend. Pod茅is dejarme en los comentarios 聽esas grandes ideas, no se lo contar茅 a nadie ;-P

 

Si necesitas desarrollar una aplicaci贸n m贸vil no dudes en solicitarme un presupuesto sin compromiso:

Un saludo, y si a煤n no lo has hecho no olvides suscribirte a mi blog para no perderte los pr贸ximos posts 聽:-),

Tambi茅n puedes seguirme en Twitter en 鈥嶡revigames y no olvides que me ayudas mucho聽si compartes este post en las redes sociales.

27 comentarios en “Tutorial de Ionic – Firebase – parte 2: Database – Guardar nuestros sitios en la nube.

  1. Genial!!! He completado todo el tutorial desde el inicio en el que creamos la app de sitios sin ning煤n problema, todo perfecto. Esto no me hab铆a pasado nunca, siempre tutoriales incompletos y hechos deprisa. Te felicito.

    Aprovecho para ver si puedes ayudarme con una dudilla, despu茅s de ver lo genial que son las bases de datos realtime de Firebase.

    Tengo en la cabeza una aplicaci贸n pero no se muy bien si Firebase es la mejor opci贸n o no a la hora de almacenar lo que quiero. Esta aplicaci贸n quiero que muestre una galer铆a de im谩genes almacenadas en alg煤n sitio (Firebase? Cloudinary?). Todos los usuarios ver谩n las mismas im谩genes en la app pero cada uno podr谩 tener estas im谩genes en un estado diferente, por ejemplo visto, no visto, modificado. 驴Como crees que es la mejor opci贸n para hacer algo as铆?

    Muchas gracias!!

    1. Hola Sergio, me alegro que el tutorial te haya sido de utilidad,
      En cuanto a lo que me preguntas la verdad es que no he usado Cloudinary as铆 que no puedo darte una opini贸n, lo que si te dir铆a que a pesar de que en este ejemplo del tutorial almacenamos las im谩genes de los sitios directamente en la base de datos en formato base64, no es una buena idea cuando son muchas las im谩genes que vas a almacenar, creo que lo ideal es tener las im谩genes almacenadas en otro sitio, puede ser en firebase Storage o otro sitio y en la base de datos guardar la url de acceso a cada imagen.
      Espero que tengas suerte con tu idea y si quieres comentar por aqu铆 que soluci贸n has utilizado al final por si sirve de ayuda a alguien ser谩s bien recibido.

      Un saludo y gracias por comentar :)https://reviblogdotnet.wordpress.com/wp-admin/edit-comments.php#comments-form

  2. Eduardo te felicito por este Tutorial, me ha sido de gran utilidad, pero… sabes de alg煤n manual, libro de Ionic y Firebase?? que pueda ser recomendable… Te lo agradecer铆a , pues estoy muy interesado en aprenderlo a fondo, Muchas Gracias por todo Eduardo.

    1. Hola Jos茅 Mar铆a,

      La verdad es que buscando libros sobre ionic 2 solo he encontrado un par de ellos en amazon en ingles y bastante caros, si lo que te interesa es aprenderlo a fondo, teniendo ya una base lo mejor es acudir directamente a la documentaci贸n oficial de ionic y firebase respectivamente, no obstante si encuentras alg煤n libro o tutorial al respecto que creas que merece la pena no dudes en recomendarlo en los comentarios para todos los que podamos estar interesados.

      Muchas gracias por comentar.

      Un saludo

  3. Hola Eduardo, estoy intentando a帽adir cosas a la app de tu tutorial para aprende m谩s pero me encuentro con problemas para acceder a la base de datos de firebase cuando tengo un nivel m谩s, a ver si me puedes echar una manita.

    En tu tutorial para acceder a la base de datos de firebase utilizas:

    return this.afdb.list(‘sitios/’+this.auth.getUser());

    Pero como acceder铆a si mi json tiene otro nivel?

    He eliminado los usuarios para simplificar

    Por ejemplo :

    {
    “sitios”: {
    “Barcelona”:{
    “sitio1”:{
    “name”: “SH6-01”,
    “url-foto”: “http://sitio1.png”},
    “sitio2”:{
    “name”: “SH6-01”,
    “url-foto”: “http://sitio1.png”}
    },
    “Madrid”:{
    “sitio1”:{
    “name”: “SH6-01”,
    “url-foto”: “http://sitio1.png”
    }
    }
    }
    }

    En mi html me gustar铆a separar los ngFor por Ciudades, es decir, que me liste los de Barcelona por un lado y los de Madrid por otro por si luego me interesa filtrar una b煤squeda por ejemplo, pero si lo hago de esta forma me da error, he buscado mucha info pero no me aclaro.

  4. Hola Eduardo, estoy aprendiendo Ionic3 con tu tutorial y encuentro un error al intentar borrar un sitio. La pregunta es 驴como le pasas el id del sitio que se quiere borrar? Justo no est谩 el HTML con el template (驴listado.html tal ves?) y la llamada al m茅todo borrarSitio(id).
    He intentado algo as铆: on-tap=”borrarSitio({{item.$key}})” pero no funciona, tira:
    Error: ExpressionChangedAfterItHasBeenCheckedError: Expression has changed after it was checked. Previous value: ‘undefined’. Current value: ‘[[item.$key]]’.
    He intentado con [[]] y con {{}}, y es lo mismo.
    Alguna idea?
    Gracias de antemano.

    1. Hola Adri谩n, Si has seguido el tutorial completo no tienes que modificar el html de la pagina listado. Para eliminar un sitio lo haces as铆 (click)=”borrarSitio(sitio.id)”.
      El html los puedes ver en este post cuando utiliz谩bamos la base de datos local en lugar de firebase:
      https://reviblog.net/2017/06/02/tutorial-de-ionic-2-crear-una-aplicacion-para-guardar-nuestros-sitios-geolocalizados-parte-8-eliminar-un-sitio-desde-el-listado-deslizando-el-item-con-itemsliding/

      Un saludo

  5. Muchas gracias por el curso, es una pasada, me ha encantado. He tenido un problema al final, 驴me podr铆as ayudar?

    Al tratar de suscribirme a los sitios mediante el observable, me dice da un par de errores. Es como si no existiera la propiedad subscribe para AngularFireList.

    A la hora de hacer el import de FirebaseListObservable en firebase-db.ts tambi茅n me falla, me dice que no tiene ese miembro exportable.

    [20:32:33] typescript: C:/Users/pedro/OneDrive/ionic/misSitios – firebase/src/pages/listado/listado.ts, line: 36
    Property ‘subscribe’ does not exist on type ‘AngularFireList’.

    L36: this.dbFirebase.getSitios().subscribe(sitios => {
    L37: this.sitios = sitios;

    [20:32:33] typescript: …dro/OneDrive/ionic/misSitios – firebase/src/providers/firebase-db/firebase-db.ts, line: 2
    Module ‘”C:/Users/pedro/OneDrive/ionic/misSitios – firebase/node_modules/angularfire2/database/index”‘ has
    no exported member ‘FirebaseListObservable’.

    L1: import { Injectable } from ‘@angular/core’;
    L2: import { AngularFireDatabase, FirebaseListObservable } from ‘angularfire2/database’;
    L3: import { AuthProvider } from ‘../auth/auth’;

      1. Hola Alejandra:

        Acabo de corregir la entrada, el problema era que con la 煤ltima actualizaci贸n FirebaseListObservable se ha quedado obsoleto.
        Ya he corregido el c贸digo, en firebase-db-ts hay que sustituir FirebaseListObservable por AngularFireList. Despu茅s en la funci贸n getSitios hay que a帽adirle .valueChanges() al final:

        getSitios(){
        return this.afDB.list(‘sitios/’+this.auth.getUser()).valueChanges();
        }

        Gracias por comentar.

        Un saludo

        1. en que parte se usa AngularFireList?? no logro acceder a mi base de datos..

          me sale el siguiente error:

          L2: import { Injectable } from ‘@angular/core’;
          L3: import { AngularFireDatabase,AngularFireList} from ‘angularfire2/database’;

          y me metodo es de la siguiente manera nose que parte de estoy haciendo mal :

          getSitios(){
          return this.afDB.list(‘sitios/’+this.auth.getUser()).valueChanges();
          }

          asi no pudiendo obtener mi lista para poder iterar y p贸der mostrarlo en mi .hmtl

    1. Hola Pedro, perd贸n por tardar tanto en responder, no hab铆a encontrado tiempo para investigar sobre este error.

      Con la 煤ltima actualizaci贸n FirebaseListObservable se ha quedado obsoleto.
      Ya he corregido el c贸digo, en firebase-db-ts hay que sustituir FirebaseListObservable por AngularFireList. Despu茅s en la funci贸n getSitios hay que a帽adirle .valueChanges() al final:

      getSitios(){
      return this.afDB.list(‘sitios/’+this.auth.getUser()).valueChanges();
      }

      Gracias por comentar.

      Un saludo

    1. Hola, se que escribiste hace mucho este comentario, pero estoy intentando hacer lo que vos consultabas y no puedo lograrlo, encontraste solucion? graciasss

  6. Hola, como estas? necesito hacer un consulta, Yo estoy guiandome con los tutoriales y hay algo que no se como logralo.
    yo traslade todo lo que fui aprendiendo aca , a una aplicacion que tengo que entregar para la facultad.
    en mi caso, el usuario crea publicaciones y se muestran en un card con un boton de publicar, en la base de datos se guarda igual que los sitios , como tu explicaste. Cuando el usuario hace click en el boton de “Publicar”, necesito obtener los datos de esa publicacion y es ahi donde no puedo hacerlo, puedo traer todas las publicaciones del usuario, pero no de esa publicacion en particular.Muchas graciasss

  7. Hola:
    Segu铆 el tutorial al pie de la letra, pero tengo un problema al momento de guardar en firebase (en sqlite se guarda correctamente).

    Al momento de agregar un nuevo sitio, toma correctamente las coordenadas y saca la fotograf铆a, cuando presiono el bot贸n de “guardar sitio” simplemente no lo activa y no guarda nada.

    Al debuggear la app me arroja el siguiente error:
    ERROR CONTEXT DebugContext_ {view: Object, nodeIndex: 58, nodeDef: Object, elDef: Object, elView: Object}View_ModalNuevoSitioPage_0 @ ModalNuevoSitioPage.html:31proxyClass @ vendor.js:102495DebugContext_.logError @ vendor.js:15412ErrorHandler.handleError @ vendor.js:1889IonicErrorHandler.handleError @ vendor.js:159918dispatchEvent @ vendor.js:10382(anonymous function) @ vendor.js:12717schedulerFn @ vendor.js:4728SafeSubscriber.__tryOrUnsub @ vendor.js:20820SafeSubscriber.next @ vendor.js:20758Subscriber._next @ vendor.js:20696Subscriber.next @ vendor.js:20660Subject.next @ vendor.js:24106EventEmitter.emit @ vendor.js:4696NgForm.onSubmit @ vendor.js:32363(anonymous function) @ ModalNuevoSitioPage.html:31handleEvent @ vendor.js:13963callWithDebugContext @ vendor.js:15472debugHandleEvent @ vendor.js:15059dispatchEvent @ vendor.js:10378(anonymous function) @ vendor.js:11003(anonymous function) @ vendor.js:40717t.invokeTask @ polyfills.js:3zone._inner.zone._inner.fork.onInvokeTask @ vendor.js:5125t.invokeTask @ polyfills.js:3r.runTask @ polyfills.js:3e.invokeTask @ polyfills.js:3p @ polyfills.js:2v @ polyfills.js:2
    ModalNuevoSitioPage.html:31 ERROR Error: Reference.set failed: First argument contains undefined in property ‘sitios.IFwhT6NARLdQL5DwpXJWZJPDxX33.1543958848027.address’
    at validateFirebaseData (http://localhost:8080/build/vendor.js:140684:15)
    at http://localhost:8080/build/vendor.js:140730:13
    at Object.forEach (http://localhost:8080/build/vendor.js:76606:13)
    at validateFirebaseData (http://localhost:8080/build/vendor.js:140713:14)
    at validateFirebaseDataArg (http://localhost:8080/build/vendor.js:140672:5)
    at Reference.set (http://localhost:8080/build/vendor.js:153211:9)
    at FirebaseDbProvider.webpackJsonp.288.FirebaseDbProvider.guardaSitio (http://localhost:8080/build/main.js:176:89)
    at ModalNuevoSitioPage.webpackJsonp.513.ModalNuevoSitioPage.guardarSitio (http://localhost:8080/build/0.js:137:25)
    at Object.eval [as handleEvent] (ng:///ModalNuevoSitioPageModule/ModalNuevoSitioPage.ngfactory.js:95:27)
    at handleEvent (http://localhost:8080/build/vendor.js:13963:155)

  8. Hola, bueno el tutorial… pero tengo problemas al momento de mostrar la lista desde firebase…

    me da el siguiente error…
    Uncaught TypeError: Object(…) is not a function
    at SwitchMapSubscriber.project

    al momento de ir a la funcion getSitios…

    me ayudas?!

    1. hola walter si te aparece este error Uncaught TypeError: Object(鈥) is not a function es por que no tienes permisos con Uncaught.
      a si instalarlos con este comando

      npm install rxjs@6 rxjs-compat@6 –save

Deja una respuesta

Tu direcci贸n de correo electr贸nico no ser谩 publicada. Los campos obligatorios est谩n marcados con *

Este sitio usa Akismet para reducir el spam. Aprende c贸mo se procesan los datos de tus comentarios.