Hola a todos, por diversos motivos he tenido abandonado el blog durante una temporada, por fin estoy de vuelta y me dispongo a seguir con el tutorial de Ionic que dejé a medias.
En el último post vimos cómo navegar entre páginas con Ionic, hoy vamos a seguir con el tutorial aprendiendo a utilizar los menús laterales.
En el siguiente enlace tienes el índice para acceder al resto de entradas de este tutorial:
Podemos crear un proyecto de ionic utilizando la plantilla sidemenu y ya nos crearía la estructura de una aplicación con un menú lateral y dos páginas de ejemplo.
Sin embargo, para entender mejor cómo funciona vamos a crear un proyecto con la plantilla blank y vamos a añadir nosotros los componentes necesarios para generar un menú lateral.
Lo primero que vamos ha hacer es crear un nuevo proyecto:
ionic start menu blank
Seleccionamos Angular y le podemos decir que no queremos integrar Capacitor, para este ejemplo no lo necesitamos.
Bien, una vez se haya generado el proyecto nos situamos desde la consola dentro de la carpeta menú que se acaba de crear.
Como por defecto ya nos crea la página home, vamos a crear otra página que se llame listado:
ionic g page listado
La idea es tener dos opciones en el menú, una que nos lleve a la página de inicio (home) y otra que nos lleve a una segunda página, en este caso la página listado que acabamos de crear.
La plantilla principal de nuestra aplicación, la que se va a cargar siempre al inicio se encuentra en el archivo app.component.html.
Si echamos un vistazo al contenido de app.component.html vemos que contiene lo siguiente:
Dentro de ion-router-outlet se carga el contenido de la página que esté activa en ese momento, es decir la que indique la ruta actual.
Aquí vamos a añadir el menú, que dependiendo de la opción seleccionada cambiará la ruta para mostrar dentro de ion-router-oulet la página que hayamos seleccionado.
Editamos app.component.html y añadimos el siguiente código:
Lo primero que hacemos es envolver todo en una etiqueta ion-split-pane, esto permite adaptarse a pantallas más grandes (como tabletas) y muestra el menú justo al lado de su contenido. Le asignamos la propiedad contentId=”main-content” que serà el id que le vamos a asignar a la etiqueta ion-router-outlet donde irá el contenido de la aplicación.
Después tenemos ion-menu que es el componente que contiene el menú y al que asignaremos tambien el parámetro contentId=”main-content”, dentro del mismo añadimos su contenido igual que si sería una página, hemos añadido un ion-header con un toolbar y dentro el título del menú.
Después tenemos un ion-content y dentro hemos creado un listado con dos items con las opciones del menú.
Como vimos en el anterior capítulo routerDirection sirve para indicar la dirección de la animación.
En el parámetro routerLink de cada item definimos la ruta que tenemos que cargar al pulsar en el.
Observa que la ruta está entre comillas simples dentro de las comillas dobles, esto es para que lo tome como un literal en lugar de una variable.
También podríamos definir una variable con un array de opciones con sus rutas y hacer un bucle para mostrar las opciones, pero para simplificar hemos creado las dos opciones a mano directamente.
Si ejecutamos la aplicación en un navegador de escritorio con ionic serve se mostrará el menú siempre visible a la izquierda del contenido, sin embargo si ejecutamos ahora la aplicación con ionic serve -l a tamaño móvil no veremos nada especial, solo la página home, para poder ver el menú tenemos que crear un botón para hacer que se muestre el menú. Para ello vamos a modificar el archivo home.page.html, y añadimos un botón especial llamado ion-menu-button que se encarga de abrir y cerrar el menú, de paso vamos a eliminar todo lo que hay dentro de ion-content y a añadir un texto en el contenido para indicar que es la página de inicio:
<ion-header><ion-toolbar><ion-buttons slot="start"><ion-menu-button></ion-menu-button></ion-buttons><ion-title>
Ionic Blank
</ion-title></ion-toolbar></ion-header><ion-content><div class="ion-padding"><p>Yo soy la página de inicio</p></div></ion-content>
Para finalizar vamos a modificar también la plantilla de la página listado para añadir a la cabecera el botón del menú y de paso añadimos un pequeño listado en el contenido para que haga honor a su nombre, editamos el archivo listado.page.html y añadimos lo siguiente:
<ion-header><ion-toolbar> <ion-buttons slot="start">
<ion-menu-button></ion-menu-button>
</ion-buttons>
<ion-title>listado</ion-title></ion-toolbar></ion-header><ion-content><ion-list>
<ion-item>
<ion-label>
Item 1 del listado
</ion-label>
</ion-item>
<ion-item>
<ion-label>
Item 2 del listado
</ion-label>
</ion-item>
<ion-item>
<ion-label>
Item 2 del listado
</ion-label>
</ion-item>
<ion-item>
<ion-label>
Item 3 del listado
</ion-label>
</ion-item>
</ion-list></ion-content>
Ahora si ejecutamos ionic serve -l veremos nuestro menú en acción:
Puedes descargar o clonar este proyecto desde GitHub en el siguiente link:
En posts anteriores hemos aprendido a crear nuestras apps multiplataforma con Ionic.
Ionic nos ofrece un montón de componentes ya creados para utilizar en nuestras apps y realmente nos permiten con poco esfuerzo crear una interfaz funcional para nuestras aplicaciones.
En el siguiente enlace tienes el índice para acceder al resto de entradas de este tutorial:
Sin embargo hay momentos que puede interesarnos crear nuestros propios componentes personalizados.
Un componente es simplemente algo que podemos mostrar las veces que queramos en la pantalla, como si fuese una etiqueta html, solo que a su vez un componente puede estar formado por etiquetas html y otros componentes.
Para ver mejor como podemos crear nuestro propios componentes personalizados en Ionic vamos a crear un proyecto de prueba al que vamos a llamar miComponente:
ionic start miComponente blank
Una vez creado el proyecto si entramos en home.ts veremos esto:
import{ Component } from '@angular/core';import{ NavController } from 'ionic-angular';@Component({selector:'page-home',templateUrl:'home.html'})exportclass HomePage {
constructor(publicnavCtrl: NavController){}}
En Ionic todo son componentes, de hecho las páginas de nuestra aplicación son componentes, si nos fijamos tiene un decorador @Component por lo que podemos ver que la propia pagina es un componente que tiene el selector ‘page-home’ y como plantilla utiliza el archivo home.html.
Vamos a crear un sencillo componente al que vamos a llamar saludar, para ello vamos a echar mano de ionic generator, nos situamos dentro la carpeta de nuestro proyecto en la consola de comandos y tecleamos lo siguiente:
ionic g component saluda
Con esto se habrá creado una nueva carpeta llamada components y dentro una carpeta llamada saluda que al igual que las páginas contiene un archivo .ts como controlador, un archivo .scss para los estilos y su plantilla .html.
Si observamos lo que contiene el archivo saluda.html vemos que simplemente muestra el contenido de la variable text dentro de un div:
<!-- Generated template for the SaludaComponent component --><div>
{{text}}
</div>
Vemos que text está definida en el controlador saluda.ts y contiene la famosa frase “Hello Word”
import{ Component } from '@angular/core';/** * Generated class for the SaludaComponent component. * * See https://angular.io/api/core/Component for more info on Angular * Components.*/@Component({selector:'saluda',templateUrl:'saluda.html'})exportclass SaludaComponent {text:string;
constructor(){
console.log('Hello SaludaComponent Component');this.text = 'Hello World';}}
Como vemos el controlador de un componente es prácticamente igual que el de una página.
Tenemos el decorador @Component donde se indica que su selector es ‘saluda‘ y la plantilla que utiliza es saluda.html.
Para poderlo utilizar tenemos que importar y declarar el componente en app.module.ts:
import{ BrowserModule } from '@angular/platform-browser';import{ ErrorHandler, NgModule } from '@angular/core';import{ IonicApp, IonicErrorHandler, IonicModule } from 'ionic-angular';import{ SplashScreen } from '@ionic-native/splash-screen';import{ StatusBar } from '@ionic-native/status-bar';import{ MyApp } from './app.component';import{ HomePage } from '../pages/home/home';import { SaludaComponent } from '../components/saluda/saluda';
@NgModule({declarations:[
MyApp,
HomePage,SaludaComponent],imports:[
BrowserModule,
IonicModule.forRoot(MyApp)],bootstrap:[IonicApp],entryComponents:[
MyApp,
HomePage
],providers:[
StatusBar,
SplashScreen,{provide: ErrorHandler,useClass: IonicErrorHandler}]})exportclass AppModule {}
Para utilizarlo en la página home editamos el archivo home.html y añadimos la etiqueta con el componente que acabamos de crear:
Luego en el controlador definimos el parámetro de entrada con el decorador Input de la siguiente manera:
import{ Component, Input } from '@angular/core';/** * Generated class for the SaludaComponent component. * * See https://angular.io/api/core/Component for more info on Angular * Components.*/@Component({selector:'saluda',templateUrl:'saluda.html'})exportclass SaludaComponent {text:string;@Input('nombre') nombre : string;
constructor(){
console.log('Hello SaludaComponent Component');this.text='Hello World';}}
Para poder utilizar el decorador Input debemos importarlo primero.
Ahora podemos hacer que en lugar de saludar al mundo con «Hello Word» salude a la persona que recibamos en el parámetro nombre:
import{ Component, Input } from '@angular/core';/** * Generated class for the SaludaComponent component. * * See https://angular.io/api/core/Component for more info on Angular * Components.*/@Component({selector:'saluda',templateUrl:'saluda.html'})exportclass SaludaComponent {text:string;@Input('nombre')nombre :string;
constructor(){
console.log('Hello SaludaComponent Component');this.text = 'Hola '+this.nombre;}}
Bien, si como en el ejemplo hemos pasado «Eduardo» al parámetro nombre cabría esperar ver en pantalla «Hola Eduardo», sin embargo comprobamos que muestra «Hola undefined», a no ser que tus padres te hayan puesto de nombre undefined hay algo que no está funcionando.
Eso eso es porque estamos accediendo a la variable this.nombre desde el constructor, y en el momento que se ejecuta el constructor aun no están accesibles los parámetros que recibimos en nuestro componente, para ello utilizamos ngOnInit:
/** * Generated class for the SaludaComponent component. * * See https://angular.io/api/core/Component for more info on Angular * Components. */@Component({
selector:'saluda',
templateUrl:'saluda.html'})exportclass SaludaComponent { text:string;@Input('nombre') nombre :string;
constructor(){
console.log('Hello SaludaComponent Component');} ngOnInit(){
this.text = 'Hola '+this.nombre;
}}
Ahora podemos comprobar que muestra el nombre que le hayamos pasado.
También podemos utilizar la la variable nombre directamente en la plantilla de nuestro componente de esta manera:
<!-- Generated template for the SaludaComponent component --><div> Hola {{ nombre }}</div>
Por ultimo si en lugar de pasarle directamente el nombre al componente queremos utilizar una variable debemos poner el parámetro entre corchetes , por ejemplo imaginemos que tenemos un array de usuarios y queremos saludarles a todos, en home.ts definiriamos un array de usuarios:
Ahora en home.html podemos recorrer el array con *ngFor y mostrar nuestro componente saludo pasándole la variable usuario.nombre:
<ion-header><ion-navbar><ion-title>
Ionic Blank
</ion-title></ion-navbar></ion-header><ion-content padding><saluda *ngFor="let usuario of usuarios" [nombre]="usuario.nombre"></saluda></ion-content>
Como podemos ver en este caso el parámetro nombre va entre corchetes [] ya que lo que le pasamos no es un texto literal sino una variable.
Si probamos este ejemplo veremos algo como esto:
Este ejemplo es muy sencillo y es solo para explicar como funcionan los componentes en Ionic, evidentemente no merece la pena crear un componente que solo contenga un div y un texto, pero podemos ampliar nuestro componente añadiendo una imagen o una ficha completa con los datos del usuario, o cualquier otro elemento que se nos ocurra.
Espero que estos sencillos ejemplos sirvan para comprender como crear componentes personalizados en Ionic.
Si necesitas desarrollar una aplicación móvil no dudes en solicitarme un presupuesto sin compromiso:
Ahora en app.module.ts tenemos que añadir los siguientes imports:
import{ TranslateModule, TranslateLoader } from "@ngx-translate/core";import{ TranslateHttpLoader } from "@ngx-translate/http-loader";import{ HttpClient, HttpClientModule } from "@angular/common/http";
Justo debajo de los imports, antes de @NgModule añadimos el siguiente código:
export function HttpLoaderFactory(httpClient: HttpClient){return new TranslateHttpLoader(httpClient,"../assets/i18n/",".json");}
Por último declaramos dentro de imports lo que esta marcado en amarillo:
El código completo de app.module.ts quedaría de la siguiente manera:
import{ BrowserModule } from '@angular/platform-browser';import{ ErrorHandler, NgModule } from '@angular/core';import{ IonicApp, IonicErrorHandler, IonicModule } from 'ionic-angular';import{ SplashScreen } from '@ionic-native/splash-screen';import{ StatusBar } from '@ionic-native/status-bar';import{ MyApp } from './app.component';import{ HomePage } from '../pages/home/home';import{ TranslateModule, TranslateLoader } from "@ngx-translate/core";import{ TranslateHttpLoader } from "@ngx-translate/http-loader";import{ HttpClient, HttpClientModule } from "@angular/common/http";exportfunction HttpLoaderFactory(httpClient: HttpClient){returnnew TranslateHttpLoader(httpClient,"../assets/i18n/",".json");}@NgModule({declarations:[
MyApp,
HomePage
],imports:[
BrowserModule,
IonicModule.forRoot(MyApp),
HttpClientModule,
TranslateModule.forRoot({loader:{provide: TranslateLoader,useFactory: HttpLoaderFactory,deps:[HttpClient]}})],bootstrap:[IonicApp],entryComponents:[
MyApp,
HomePage
],providers:[
StatusBar,
SplashScreen,{provide: ErrorHandler,useClass: IonicErrorHandler}]})exportclass AppModule {}
Ahora vamos a editar app.component.ts y añadimos el siguiente código:
import{ Component } from '@angular/core';import{ Platform } from 'ionic-angular';import{ StatusBar } from '@ionic-native/status-bar';import{ SplashScreen } from '@ionic-native/splash-screen';import { TranslateService } from '@ngx-translate/core';
import{ HomePage } from '../pages/home/home';@Component({templateUrl:'app.html'})exportclass MyApp {rootPage:any= HomePage;
constructor(platform: Platform,statusBar: StatusBar,splashScreen: SplashScreen,private translateService: TranslateService){
platform.ready().then(()=>{// Okay, so the platform is ready and our plugins are available.// Here you can do any higher level native things you might need.this.translateService.setDefaultLang('es');
this.translateService.use('es');
statusBar.styleDefault();
splashScreen.hide();});}}
Con this.translateService.setDefaultLang(‘es’); le idicamos que el idioma por defecto es el español y con this.translateService.use(‘es’); hacemos que sea el idioma seleccionado.
Dentro de la carpeta src/assets vamos a crear una carpeta llamada i18n y dentro de esta situaremos los archivos con los literales en los diferentes idiomas, en este ejemplo vamos a usar inglés y español, por lo que vamos a crear dos archivos llamados en.json para inglés y es.json para español:
En en.json pondremos lo siguiente:
{"HOLA":"Hi {{ value }}","IDIOMA":"Language","BIENVENIDO":"Welcome"}
Y en es.json:
{"HOLA":"Hola {{ value }}","IDIOMA":"Idioma","BIENVENIDO":"Bienvenido"}
Como puedes observar es un archivo en formato json donde la clave es lo que escribiremos en la vista y el valor es lo que se mostrará en función del idioma seleccionado.
Como puedes ver HOLA se traduce como «Hola {{ value }}», donde value se sustituirá por el valor pasado, veremos un poco más adelante como se utiliza.
Ya estamos preparados para traducir nuestra app.
Vamos a modificar home.html y vamos a crear un ejemplo sencillo donde vamos a tener un elemento ion-card que simplemente nos da la Bienvenida y nos saluda y un selector para cambiar de idioma:
Como vemos en la etiqueta ion-select le decimos que en el evento (ionChange) llame a la función cambioIdioma($event), $event contendrá la opción seleccionada.
Para traducir las cadenas al idioma seleccionado utilizamos en pipe o barra vertical ‘|’ seguido de la palabra translate que es filtro que se aplica.
Como comenté antes podemos pasarle un valor al filtro translate de la siguiente manera:
{{ ‘HOLA’ | translate:{value: ‘Eduardo’} }}
Con esto le estamos diciendo que traduzca la cadena HOLA y le pase al fintro el value ‘Eduardo’.
Al ir a buscar el valor en el archivo json sustituirá valúe por ‘Eduardo’:
«HOLA»:«Hi {{ value }}»,
Esto puede servirnos de ayuda cuando queremos traducir cadenas mostrando un valor que dependiendo del idioma se debe mostrar en una posición diferente de la cadena, por ejemplo la frase «Este es el coche de Eduardo» en inglés sería «this is Eduardo’s car».
Por lo tanto en inglés podríamos pasarle el nombre y traducirlo así: «this is {{ value }}’s car»,
Mientras que en español sería «Este es el coche de {{ value }}»
Bien, ahora solo nos queda definir la función cambioIdioma en el controlador home.ts, para poder cambiar de idioma necesitaremos importar TranslateService e inyectarlo en el constructor:
import{ Component } from '@angular/core';import{ NavController } from 'ionic-angular';import { TranslateService } from '@ngx-translate/core';
@Component({selector:'page-home',templateUrl:'home.html'})exportclass HomePage {
constructor(publicnavCtrl: NavController,private translateService: TranslateService){}cambioIdioma(selectedValue){
this.translateService.use(selectedValue);
}}
Con selectedValue es el idioma que hemos seleccionado en el select y con this.translateService.use(selectedValue) le estamos diciendo que utilice el idioma que le pasamos.
Ya podemos probar nuestro pequeño ejemplo, ejecutando ionic serve -l desde consola veremos algo como esto en nuestro navegador:
Ejemplo de app multi idioma con ionic
Por último, como extra si desde el controlador necesitamos traducir una cadena podemos utilizar this.translateService.instant().
Por ejemplo si queremos mostrar un loading y que se muestra cargando en el idioma seleccionado, teniendo ya definido el literal cargando en los ficheros .json podemos hacer lo siguiente:
Hay que tener e cuenta que translate.instant es síncrono, por lo que tenemos que estar seguros de que los archivos lang han sido cargados para obtener traducciones.
En su lugar también se puede utilizar translate.get, que devuelve un elemento observable.
El post de hoy es por cortesía de Miguel Escribano.
Miguel ha realizado una app en ionic para consultar las noticias de menéame que está realmente bien y que podéis encontrar en google play en el siguiente enlace:
Bién, Miguel que ha querido colaborar aportando una directiva para mostrar u ocultar un menú o barra de herramientas al hacer scroll:
Una directiva es un tipo de componente pensado para cambiar el comportamiento de un elemento ya existente en el DOM. A diferencia de un componente normal este no necesita de una plantilla sino que se incrustara en una existente para manipularla.
El objetivo aquí es esconder una barra de navegación al hacer scroll hacia abajo y que aparezca cuando hacemos scroll hacia arriba.
En ionic el evento de scroll se produce en el content, por tanto dicha barra ha de encontrarse dentro de ion-content.
Vamos a crear un proyecto de prueba para mostrar como funciona esta directiva:
ionic start hideMenu blank
Vamos a editar home.ts y le vamos a añadir un array con los items que mostraremos en el listado, por ejemplo una lista de videojuegos:
import{ Component } from '@angular/core';import{ NavController } from 'ionic-angular';
@Component({
selector:'page-home',
templateUrl:'home.html'})exportclass HomePage { items = [
'Pokemon Yellow',
'Super Metroid',
'Mega Man X',
'The Legend of Zelda',
'Pac-Man',
'Super Mario World',
'Street Fighter II',
'Half Life',
'Final Fantasy VII',
'Star Fox',
'Tetris',
'Donkey Kong III',
'GoldenEye 007',
'Doom',
'Fallout',
'GTA',
'Halo',
'Warcraft II'
];
constructor(public navCtrl: NavController){}}
Ahora vamos a editar home.html y añadimos el siguiente código en amarillo en ion-content para generar la toolbar y los items de prueba:
Como podéis ver en la etiqueta ion-content hemos añadido hide-menu que es el nombre de la directiva que vamos a crear.
Después hemos añadido una ion-toolbar con ion-segment y cuatro opciones que será la barra de menú que vamos a mostrar u ocultar.
Por ultimo mostramos un listado donde mostramos con *ngFor los items que hemos definido en el controlador.
Véase que de entrada la barra tiene la clase show-header. Incluiremos esta y hide-header en la listado.scss con la intención de hacerla aparecer y desaparecer respectivamente.
También necesitamos definir la posición de ion-tollbar como fixed.
Suponiendo que nuestro header principal (ion-header) tiene la altura 56px por defecto incluiremos lo siguiente en listado.scss:
Ya solo queda crear la directiva, para ello vamos a utilizar ionic generator:
ionic g directive hide-menu
Al generar la directiva nos habrá creado una carpeta directives y dentro estará la carpeta hide-menu con la directiva que acabamos de crear.
Necesitamos declarar la directiva en app.module.ts, por lo tanto lo editamos y añadimos lo siguiente:
import{ BrowserModule } from '@angular/platform-browser';import{ ErrorHandler, NgModule } from '@angular/core';import{ IonicApp, IonicErrorHandler, IonicModule } from 'ionic-angular';import{ SplashScreen } from '@ionic-native/splash-screen';import{ StatusBar } from '@ionic-native/status-bar';import{ MyApp } from './app.component';import{ HomePage } from '../pages/home/home';import { HideMenuDirective } from '../directives/hide-menu/hide-menu';
@NgModule({
declarations:[
MyApp,
HomePage, HideMenuDirective],
imports:[
BrowserModule,
IonicModule.forRoot(MyApp)],
bootstrap:[IonicApp],
entryComponents:[
MyApp,
HomePage
],
providers:[
StatusBar,
SplashScreen,{provide: ErrorHandler, useClass: IonicErrorHandler}]})exportclass AppModule {}
Ahora editamos el archivo hide-menu.ts de nuestra directivay vamos a importar e inyectar en el constructor ElementRef, Renderer2, que necesitaremos para manipular los elementos de la vista:
import{ Directive,ElementRef, Renderer2} from '@angular/core';/** * Generated class for the HideMenuDirective directive. * * See https://angular.io/api/core/Directive for more info on Angular * Directives. */
@Directive({
selector:'[hide-menu]'// Attribute selector})exportclass HideMenuDirective {
constructor(public element:ElementRef, public renderer:Renderer2){
console.log('Hello HideMenuDirective Directive');}}
Vemos que en el decorador @Directive viene definido el selector que es el que tenemos que poner en el elemento de la vista al que queremos aplicar la directiva.
Ahora en la definición de la directiva a la propiedad host le vamos a asignar el evento ionScroll y le indicamos que ejecute la función handleScroll que definiremos después. Host hace referencia al elemento donde estamos aplicando la directiva, en este caso se lo estamos asignando al elemento ion-content:
@Directive({
selector:'[hide-menu]', // Selector de la directivahost: {
'(ionScroll)': 'handleScroll($event)' // Captura el evento scroll (ionScroll) dentro de ion content y envía el evento a su manejador handleScroll
}})
Ahora necesitamos definir tres variables:
toolBarRef – Hace referencia a la toolbar que vamos a mostrar u ocultar.
storedScroll – Guardará la posición del scroll.
threshold – Contendrá la distancia que tenemos que mover el scroll para que se oculte la barra.
exportclass HideMenuDirective {private toolBarRef:any;
private storedScroll: number = 0;
private threshold: number = 10;
constructor(public element:ElementRef,public renderer:Renderer2){}
Una vez definidas las variables en ngOnInit hacemos que toolBarRef referencie al elemento del DOM que contiene la barra, ngOnInit se ejecuta una única vez al iniciar, es parecido al constructor:
ngOnInit(){//Con esto conseguimos referenciar la barra de navegacion mediante su clase.this.toolBarRef =this.element.nativeElement.getElementsByClassName("toolbar")[0];}
Una vez hecho esto ya podemos definir la función handleScroll que como hemos indicado se ejecutará al hacer scroll sobre el elemento ion-content al que hemos asignado la directiva:
handleScroll(event){if(event.scrollTop -this.storedScroll >this.threshold){//al hacer scroll down hace desaparecer la barra mediante clasesthis.renderer.addClass(this.toolBarRef,'hide-header');this.renderer.removeClass(this.toolBarRef,'show-header');}elseif(event.scrollTop -this.storedScroll <0){//al hacer scroll up la hace aparecer de nuevothis.renderer.removeClass(this.toolBarRef,'hide-header');}//actualizmos la ultima posicion conocida del scroll proveniente del eventothis.storedScroll = event.scrollTop;}
En esta función comprobamos si la posición actual del scroll (event.scrollTop) menos la posición anterior es mayor que el limite (threshold), si es así es que estamos haciendo scroll hacia abajo por lo tanto con this.renderer.addClass le añadimos a la toolbar la clase hide-header que hará que se oculte la barra y con removeClass eliminamos la clase show-header que tenia.
En caso contrario significa que estamos haciendo scroll hacia arriba por lo tanto eliminamos la clase hide-header que oculta la barra, lo que hará que esta se vuelva a mostrar.
El código completo de la directiva quedaría así:
import{ Directive, ElementRef, Renderer2 } from '@angular/core';
@Directive({
selector:'[hide-menu]',//selector de la directiva
host:{'(ionScroll)':'handleScroll($event)'//Captura el evento scroll (ionScroll) dentro de ion content y envia el evento a su manejador handleScroll}})exportclass HideMenuDirective {//Varaibles para referenciar la barra private toolBarRef:any;//Variables para saber la direccion del scrollprivate storedScroll: number =0;private threshold: number =10;
constructor(public element:ElementRef,public renderer:Renderer2){}
ngOnInit(){//Con esto conseguimos referenciar la barra de navegacion mediante su clase.this.toolBarRef =this.element.nativeElement.getElementsByClassName("toolbar")[0];}
handleScroll(event){if(event.scrollTop -this.storedScroll >this.threshold){//al hacer scroll down hace desaparecer la barra mediante clasesthis.renderer.addClass(this.toolBarRef,'hide-header');this.renderer.removeClass(this.toolBarRef,'show-header');}elseif(event.scrollTop -this.storedScroll <0){//al hacer scroll up la hace aparecer de nuevothis.renderer.removeClass(this.toolBarRef,'hide-header');}//actualizmos la ultima posicion conocida del scroll proveniente del eventothis.storedScroll = event.scrollTop;}}
Si ejecutáis el ejemplo con ionic serve -l obtendreis algo como esto:
Bien, eso es todo por hoy, solo me resta agradecer a Miguel Escribano por su aporte y recomendaros que descarguéis su app meneame.
En posts anteriores vimos como mostrar un mapa de Google maps en ionic, sin embargo ¿que pasa si queremos mostrar información en un mapa sin conexión?, google maps no nos podrá mostrar el mapa.
En lugar de utlizar Google maps en esta ocasión vamos a utilizar Leaflet para mostrar un mapa.
Leaflet es una biblioteca javascript de código abierto que nos permite crear mapas.
Lanzado por primera vez en 2011, es compatible con la mayoría de las plataformas móviles y de escritorio, y es compatible con HTML5 y CSS3 .
Es una de las bibliotecas de mapas de JavaScript más populares y es utilizada por los sitios web como FourSquare , Pinterest y Flickr .
Para poder mostrar un mapa offline es necesario tener alojados locálmente los titles que forman el mapa, si quieres mostrar un mapa de todo el mundo offline a día de hoy podemos afirmar que es inviable ya que eso supondría muchísimos gigas de información, sin embargo si que puede ser viable mostrar un mapa offline de una ciudad.
Si por ejemplo estás desarrollando una aplicación de turismo de una ciudad concreta donde vas a mostrar en un mapa los monumentos que merece la pena visitar en dicha ciudad, o cualquier otra información geolocalizada en un mapa, puede ser interesante el poder mostrar un mapa sin necesidad de tener conexión a Internet en ese preciso momento.
Vamos a ver como podemos solucionar esto en ionic 3, y como siempre la mejor manera de verlo es con un ejemplo.
Lo primero que vamos ha hacer es crear un nuevo proyecto en ionic que vamos a llamar mapaoffline:
ionic start mapaoffline blank
Una vez creado el en proyecto entramos en la carpeta con:
cd mapaoffline
Ahora vamos a descargar Leaflet, para ello descargamos la última versión desde la sección de descargas de su página oficial en el siguiente enlace:
Se habrá descargado un archivo .zip, antes de nada debemos descomprimirlo para extraer su contenido:
Ahora vamos a crear una carpeta llamada leaflet en src/assets y dentro vamos a copiar la carpeta images y el archivo leaflet.css.
Una vez hecho esto vamos a cargar el archivo leaflet.css en index.html:
<!DOCTYPE html><html lang="en" dir="ltr"><head><meta charset="UTF-8"><title>Ionic App</title><meta name="viewport" content="viewport-fit=cover, width=device-width, initial-scale=1.0, minimum-scale=1.0, maximum-scale=1.0, user-scalable=no"><meta name="format-detection" content="telephone=no"><meta name="msapplication-tap-highlight" content="no"><link rel="icon" type="image/x-icon" href="assets/icon/favicon.ico"><link rel="manifest" href="manifest.json"><meta name="theme-color" content="#4e8ef7"><!-- add to homescreen for ios --><meta name="apple-mobile-web-app-capable" content="yes"><meta name="apple-mobile-web-app-status-bar-style" content="black"><!-- cordova.js required for cordova apps --><script src="cordova.js"></script><!-- un-comment this code to enable service worker if ('serviceWorker' in navigator) { navigator.serviceWorker.register('service-worker.js') .then(() => console.log('service worker installed')) .catch(err => console.error('Error', err)); } --><link href="build/main.css" rel="stylesheet"><link href="assets/leaflet/leaflet.css" rel="stylesheet"></head><body><!-- Ionic's root component and where the app will load --><ion-app></ion-app><!-- The polyfills js is generated during the build process --><script src="build/polyfills.js"></script><!-- The vendor js is generated during the build process It contains all of the dependencies in node_modules --><script src="build/vendor.js"></script><!-- The main bundle js is generated during the build process --><script src="build/main.js"></script></body></html>
Ahora vamos a instalar leaflet desde consola con los siguiente comandos:
Ahora que ya tenemos instalado leaflet necesitamos descargar los tiles del mapa que vamos a mostrar, para ello vamos a echar mano de una herramienta llamada Mobile Atlas Creator (MOBAC), para descargarla accedemos al siguiente enlace: http://mobac.sourceforge.net/ y bajamos en la página hasta encontrar Download y pulsamos en latest stable version para descargar la aplicación.
Una vez descargada tenemos que descomprimir el archivo zip y dentro encontraremos el archivo ejecutable.
Al ejecutar Mobile Atlas Creator nos pide introducir un nombre para el atlas (en este caso le llamamos simplemente mapa) y el formato, tenemos que seleccionar Osmdroid ZIP.
Pulsamos Aceptar y nos mostrará un mapa, podemos mover zoom para ver mejor la zona que queremos seleccionar. Si hacemos doble click en un punto el mapa hará zoom y se centrará en ese punto, por ello para localizar la zona que queremos mostrar es mejor partir de un zoom que nos permita ver donde estamos e ir haciendo doble click hasta obtener la localización y zoom que nos interesa.
En el panel de la izquierda en la sección map source tenemos los mapas de los que podemos obtener los tiles, muchos son solo de una zona en concreto, yo para este ejemplo voy a utilizar OpenStreetMap4UMaps.eu que nos ofrece un mapa de todo el mundo.
Debajo del panel Map Source tenemos el panel Zoom Levels, aqui debemos seleccionar los niveles de zoom que queremos que tenga el mapa, cabe mencionar que cuantos más niveles de zoom mas tiles necesitaremos y por ende mas espacio ocuparán las imágenes.
Marcamos por ejemplo 11,12,13,14, y 15.
Ahora tenemos que seleccionar la porción del mapa que queremos descargar:
En la parte de arriba del mapa tenemos una barra de zoom que podemos mover para ver mejor la parte del mapa que queremos seleccionar. Con el ratón sobre el mapa seleccionamos un área.
Yo por ejemplo he seleccionado la zona de Bilbao, de está manera podré mostrar un mapa de Bilbao sin conexión.
Ahora debajo del panel Zoom Levels tenemos el panel Atlas content, aquí vamos a pulsar en el botón Add Selection lo que nos creará un Layer que si lo desplegamos vemos que contiene dentro los niveles de zoom que hemos seleccionado.
Bien, una vez que hemos seleccionado el área que queremos descargar tenemos que seleccionar Create Atlas y acto seguido comenzará a generar el atlas:
El atlas que se ha generado será un archico .zip con el nombre que le hemos dado al atlas en este caso mapa seguido de la fecha y hora en la que ha sido generado y lo encontrarás en la carpeta atlases dentro de la carpeta donde tengas Mobile Atlas Creator.
Bien, ahora vamos descomprimir el archivo zip que nos ha generado, al descomprimir vemos que dentro de la carpeta que nos ha creado hay otra carpeta llamada 4uMaps, vamos a cambiarle el nombre a la carpeta por simplemente mapa y a copiar esta carpeta dentro de la carpeta assets de nuestro proyecto:
Una vez que tenemos Los tiles copiados en la carpeta assets de nuestro proyecto ya podemos mostrarlos en el mapa.
Vamos a editar home.html e igual que hacíamos cuando creamos un mapa con google maps vamos a crear un div con id=»map» donde se renderizará el mapa:
Para crear un mapa con Leaflet utilizamos L.map(‘map’), ‘map’ es el id del div que hemos creado en la vista home.html y que es donde se va a renderizar el mapa.
Después con el metodo .setView le indicamos las coordenadas donde se tiene que posicionar el mapa, en este caso son las del centro de Bilbao.
Con L.tileLayer() añadimos al mapa una capa de tiles que va a contener los tiles del mapa que hemos descargado, como primer parámetro le pasamos la ruta donde se encuentran los tiles que puede ser una url si estamos utilizando un mapa online o la ruta donde se encuentrar alojados los archivos para mostrar el mapa offline como es el caso.
Si nos fijamos en la ruta vemos que es ‘assets/mapa/{z}/{x}/{y}.png’, z, x e y hacen referencia respectivamente al nivel de Zoom, tiles en el eje X y tiles en el eje Y.
Obtendrán el valor correspondiente automáticamente en función de la posición del mapa y al tener la carpeta de los tiles ordenada por estos parámetros no te tienes que preocupar.
Despues con L.marker creamos un marcador en en las coordenadas indicadas y le decimos que sea arratrable (draggable) y con .addTo(this.map) lo añadimos a nuestro mapa.
El código completo de home.ts quedaría así:
import{ Component } from '@angular/core';import{ NavController } from 'ionic-angular';import* as L from 'leaflet';@Component({selector:'page-home',templateUrl:'home.html'})exportclass HomePage {map;
constructor(publicnavCtrl: NavController){}
ionViewDidLoad(){this.map= L.map('map').
setView([43.2603479,-2.9334110],12);
L.tileLayer('assets/mapa/{z}/{x}/{y}.jpg',{maxZoom:15}).addTo(this.map);
L.marker([43.2603479,-2.9334110],{draggable:true}).addTo(this.map);}}
Ahora si ejecutamos nuestra app aunque no tengamos conexión a internet podemos mostrar un mapa:
Eso es todo por hoy, como siempre espero que os sea de utilidad.
Como el título del post indica hoy vamos a ver cómo generar un archivo .apk firmado para poder subirlo a google play.
Este es el último paso que debemos dar una vez tenemos desarrollada y lista nuestra aplicación para poder subirla a la tienda de aplicaciones de Google.
Android exige que todos los APK se firmen digitalmente con un certificado para poder instalarse.
Cuando firmas un APK se adjunta a este el certificado de clave pública que asocia el APK contigo y con tu clave privada correspondiente. Esto es necesario para poder lanzar cualquier actualización de la app asegurándose que provenga del autor original, por eso es importantísimo que guardemos el archivo keystore generado a buen recaudo para poder lanzar futuras actualizaciones ya que todas las aplicaciones deben usar el mismo certificado durante su vida útil.
Un keystore es un campo binario que contiene una o más claves privadas.
Si desarrollas una app nativa puedes generar el keystore firmar el apk desde Android studio, nosotros vamos a ver como firmar una aplicación generada desde ionic o apache cordova desde consola.
Para poder firmar el apk desde consola debemos seguir una serie de pasos que vamos a ver a continuación:
Lo primero que necesitamos es generar el keystore:
Si por ejemplo nuestra app se llama miapp para generar un keystore abrimos una terminal, nos situamos en la carpeta de nuestro proyecto y escribimos el siguiente comando:
miapp.keystore es el archivo que se va a generar, el alias es un nombre de identificación para tu clave, en este caso le hemos llamado miapp.
Con keysize le indicamos que el tamaño de la clave sea de 2048 bits, es recomendavle dejarlo en este valor.
Por último con -validity fijamos el período de validez de tu clave en años, creo que con 10000 años será suficiente ;-P.
Al ejecutar el comando nos pide que introduzcamos una serie de datos:
Introduzca la contraseña del almacén de claves: Volver a escribir la contraseña nueva: ¿Cuáles son su nombre y su apellido?¿Cuál es el nombre de su unidad de organización?¿Cuál es el nombre de su organización?¿Cuál es el nombre de su ciudad o localidad?¿Cuál es el nombre de su estado o provincia?¿Cuál es el código de país de dos letras de la unidad?
Te pide dos veces la contraseña, es importante que recuerdes la contraseña que has introducido ya que la necesitarás después.
Al final te muestra los datos que has introducido y te pide confirmación, le decimos que si:
Lo que os sale debe ser algo parecido a la siguiente imagen:
Bien, con esto ya hemos generado un archivo llamado miapp.keystore en la raiz de nuestro proyecto.
Ahora vamos a crear un nuevo archivo en la raiz del proyecto llamado build.json, lo creamos con nuestro editor de código y dentro escribimos el siguiente código:
El primero es para la versión de debug y «release» es para la versión final que vas a subir a la play store.
En el campo keystore debes poner la ruta del archivo .keystore que acabamos de generar, si lo has generado en la raíz solo debes de poner el nombre del archivo, en este caso miapp.keystore.
En alias ponemos el alias que hemos puesto al crear el archivo
Después en storePassword debe poner la contraseña del almacén de claves que indicaste al crear el archivo.
En password debemos poner la contraseña.
Guardamos el archivo y ya solo nos queda generar el apk firmado con el siguiente comando:
ionic cordova build android --release
Si no ha detectado errores y se ha compilado bien podrás encontrar el apk firmado que debes subir a play store en la siguiente ruta dentro de tu aplicación:
Eso es todo por hoy, espero que os haya sido de utilidad y ver vuestras apps triunfando en la play store pronto ;-).
Aprovecho para deciros que si has creado alguna app con ionic y la tienes en la play store puedes compartirlo en los comentarios, así servirá como inspiración para que otras personas puedan ver lo que se puede crear con ionic y al mismo tiempo seguro que ganáis alguna descarga extra que siempre viene bien 😉
Como diría Francisco Umbral, ¡He venido a hablar de mi libro! ;-P
Hoy vengo a anunciaros que por fin he publicado en Amazon mi libro para aprender a programar aplicaciones multiplataforma con ionic.
Ionic es un framework que nos permite crear de una manera rápida y sencilla aplicaciones móviles multiplataforma (Android, IOS, Windows, PWAs…) utilizando tecnologías web (HTML, JAVASCRIPT, CSS), por lo que si eres desarrollador web podrás reciclar tus conocimientos y crear aplicaciones móviles de una manera sencilla.
En este libro aprenderás de una manera sencilla y con una curva de aprendizaje suave todo lo necesario para crear aplicaciones móviles con ionic desde cero.
La principal ventaja de utilizar Ionic es que es multiplataforma, es decir que con un mismo código podemos generar apps para Android, IOS y Windows, por lo que el tiempo y coste de desarrollo y mantenimiento de una app se reduce sensiblemente.
Otra ventaja es que si dispones de conocimientos previos en desarrollo web frontend ya tienes medio camino andado ya que la curva de aprendizaje será mucho menor.
Además Ionic dispone de muchos componentes ya creados para que sin apenas esfuerzos puedas desarrollar una app de apariencia profesional sin necesidad de ser un gran diseñador.
El libro está en español por lo que será de especial utilidad para aquellos que no se arreglen bien con el inglés.
El propósito del libro es hacer la curva de aprendizaje lo más suave posible, empezando a desarrollar cosas prácticas desde el principio y aprendiendo cosas nuevas según las vamos necesitando en lugar de abrumaros con mucha teoría al principio sin ver su aplicación práctica, ya creo que esto puede hacer que muchos desistan por el camino.
En cambio es mucho más motivador ver que nada más empezar se puede hacer cosas que funcionan aunque sean sencillas y ir sobre la marcha aprendiendo conceptos a medida que los vamos necesitando.
Para que te hagas una idea del contenido del libro te muestro el índice con el contenido del mismo:
Introducción
¿Qué es ionic?
Ventajas de utilizar ionic para desarrollar apps
Desventajas de utilizar ionic para desarrollar apps
Diferencia entre Ionic 1, ionic 2 y 3 e Ionic 4
Cómo obtener el código de los ejemplos de este libro
Instalar ionic y las herramientas necesarias para el desarrollo
Instalar Node.js
Instalar ionic
Instalar Android studio.
En windows
Instalar Android Studio en Mac
Instalar un editor de código compatible con TypeScript
Hola Mundo en Ionic
Estructura de un proyecto Ionic
Modificando nuestro hola mundo
Mini Juego de acertar números
Personalizando el diseño de nuestra aplicación
Variables SASS y Variables CSS4
Colores
Utilidades CSS – Estilos predefinidos
Alineación del texto
Transformación de texto
Atributos de Texto según tamaño de pantalla
Emplazamiento de elementos
Elementos float
Elementos Flotantes según tamaño de pantalla
Visualización de elementos
Visualización u ocultación de elementos en función del tamaño de la pantalla
Espaciado del contenido
Padding
Margin
Navegación
Ionic Generator
Navegar entre páginas utilizando routerLink en la plantilla html
Navegar entre páginas programáticamente
Volver a la página anterior
Pasando datos entre páginas
Menú lateral
Navegación por Tabs
Pipes
Creando una aplicación para guardar nuestros sitios geolocalizados
Descripción de la aplicación
Mostrando el mapa
Promesas y Async/Await
Iniciando el mapa
Añadiendo un marcador al mapa
Añadiendo FAB
Modales
Creando el formulario
Utilizando la cámara
Creando un Service
Probando nuestra aplicación misSitios en el móvil
Ejecutar nuestra aplicación en un dispositivo android:
Ejecutar nuestra aplicación en un dispositivo iOS:
Guardando nuestros sitios en una base de datos local
Ionic storage
Mostrar el detalle del sitio
Modificar nuestros sitios
Eliminar un sitio desde el listado deslizando el item con “ItemSliding”
Alerts
Preparar la app para la publicación usando capacitor
Generar el splash screen y los iconos en Android
Generar el splash screen y los iconos en iOS
Generar ejecutable firmado para poder subirlo a google play.
Ionic Native y Capacitor
Componentes personalizados
Peticiones http
http.get
Promesas y Observables
http.post
Firebase
Autenticación con correo y contraseña
Alta de usuarios
Login de usuarios
Guards: Guardián de navegación
Logout
Database: Cloud Firestore – Guardar nuestros sitios en la nube
Obtener listado de sitios de firestore.
Apache Cordova
Añadiendo plataformas
Ejecutando nuestra app en el dispositivo móvil
Ionic Native
Preparar la app para la publicación usando cordova
Generar el splash screen y los iconos
Configurando nuestra app: Modificando el archivo config.xml
Evitar rotación de pantalla
Firmar el apk para subirlo a Google Play
Generar una PWA (Aplicación Web Progresiva)
¿Que es una PWA?
Creando un hola mundo de ejemplo
Configurar la PWA
Preparar la aplicación para el entorno de producción
Alojar nuestra aplicación en Firebase Hosting:
Ahora te toca a tí
Si te ha gustado el contenido sobre ionic que he compartido en este blog y quieres tenerlo más completo y mejor organizado y de paso apoyarme ya puedes comprar este libro en amazon:
Esta semana he estado trabajando en una aplicación con ionic para un cliente.
La aplicación funcionaba estupendamente en todos los dispositivos Android donde la he probado, evidentemente en dispositivos más antiguos el funcionamiento era un poco menos fluido pero aceptable en cualquier caso, sin embargo a la hora de probar la app en un dispositivo iOS, concretamente en un iPhone 6 que tengo para probar las apps en un dispositivo real me he llevado una decepción.
La aplicación tiene que mostrar una lista con imágenes e información bastante grande, además tiene un buscador para filtrar el listado por varios campos.
El scroll no iba muy fino a pesar de utilizar [virtualScroll] para el listado, cuando filtraba el listado por algunos campos a la hora de refrescar el contenido del listado iba a trompicones y tardaba en responder… en fin, la experiencia de usuario dejaba bastante que desear.
Lo primero que he hecho es pulir el código todo lo que he podido intentando que sea lo más eficiente posible, pero no ha sido suficiente.
Investigando un poco en el blog oficial de ionic me he encontrado con WKWebView.
Podéis leer la entrada del blog de ionic en este enlace:
Como sabemos ionic utiliza apache cordova que a su vez utiliza la webview del sistema para mostrar el contenido de nuestra aplicación.
Actualmente, la plataforma iOS proporciona dos webviews diferentes.
Está la webview más antigua (y más lenta) llamada «UIWebView» y otra mas nueva llamada «WKWebView«.
El navegador web predeterminado de iOS es Safari, internamente Safari utiliza WKWebView, sin embargo ionic debido a diversas incompatibilidades y problemas técnicos utiliza UIWebView.
WKWebView es más rápida que UIWebView, además Apple proporciona actualizaciones en cada versión de iOS.
Para utilizar WKWebView solo tenemos que instalar en nuestra aplicación un plugin que proporciona ionic-team.
Para instalar el plugin desde consola ejecutamos el siguiente comando:
Solo con instalar este plugin mi aplicación iba muchísimo mas fluida en mi iPhone.
Probad vuestra aplicación con este plugin y si todo va bien perfecto, sin embargo yo tuve problemas con CORS (Cross Origin Resource Sharing) al hacer peticiones al servidor ya que yo no tenia acceso para cambiar nada en el servidor y por lo tanto no podía cambiar las cabeceras de respuesta del servidor para aceptar peticiones cross origin.
Después en app.module.ts tendríamos que añadir lo siguiente:
import { NgModule } from '@angular/core';
import { NativeHttpFallback, NativeHttpModule } from 'ionic-native-http-connection-backend';
import { RequestOptions, Http } from '@angular/http';@NgModule({ declarations:[], imports:[ NativeHttpModule], bootstrap:[], entryComponents:[], providers:[{provide: Http, useClass: Http, deps:[NativeHttpFallback, RequestOptions]}],})
export class AppModule {}
Una vez hecho esto ya podemos realizar peticiones http sin problemas, si quieres saber como relizar peticiones http con ionic puedes consultar el siguiente post: Tutorial de Ionic – Peticiones http – API REST
Con estas dos cosas he conseguido que la aplicación funcione correctamente y con una fluidez mas que aceptable en iOS.
Bueno, por hoy aquí lo dejo con estos pequeños consejos, espero que os sea útil.
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()exportclass FirebaseDbProvider {
constructor(publicafDB: 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(){returnthis.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:
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',})exportclass ModalNuevoSitioPage {coords :any={lat:0,lng:0}address:string;description:string='';foto:any='';
constructor(publicnavCtrl: NavController,publicnavParams: NavParams,privateviewCtrl : ViewController,privatecamera: Camera,// private db: DbProviderprivatedbFirebase :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();returnnew Promise(function(resolve, reject){
geocoder.geocode({'location': coords},function(results, status){// llamado asincronamenteif(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 stringthis.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:
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',})exportclass ListadoPage {sitios:any;
constructor(publicnavCtrl: NavController,publicnavParams: NavParams,publicdb : DbProvider,publicmodalCtrl : ModalController,publicalertCtrl : AlertController,publicdbFirebase :FirebaseDbProvider,){}
Ahora en la función ionViewDidEnter() vamos a sustituir this.db.getSitios().then((res)=>{…}) por lo siguiente:
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:
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',})exportclass ModalDetalleSitioPage {sitio:any;edit : boolean =false;
constructor(publicnavCtrl: NavController,publicnavParams: NavParams,privateviewCtrl : ViewController,privatelaunchNavigator : LaunchNavigator,privatecamera: Camera,// private db: DbProvider,privatedbFirebase :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 stringthis.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 firebasethis.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
Hola a todos, en el último post vimos como comunicarnos con el backend a través de peticiones http, Hoy vamos a aprender a utilizar Firebase como backend.
Firebase es una plataforma de Google que nos ofrece un BaaS (Backend as a Service), lo que nos permite librarnos de la tarea de tener nuestro propio servidor y programar toda la lógica del backend, autenticación de usuarios, etc, ahorrando tiempo e infraestructura.
Firebase nos permite tener una base de datos en la nube y ver los cambios que se produzcan en tiempo real, entre otros servicios también ofrece almacenamiento de archivos en la nube, mensajería, hosting y autenticación de usuarios.
Para aprender a integrar firebase con Ionic vamos a retomar nuestra App de guardar sitios y vamos ha hacer que nuestros sitios se guarden en la base de datos de firebase para tenerlos almacenados en la nube en lugar de localmente.
Para ello tenemos también que crear un usuario y autenticarnos para que en la base de datos cada usuarios tenga sus sitios guardados.
Vamos a empezar por la autenticación de usuarios, pero antes de nada debemos crear una aplicación en firebase.
Para crear una aplicación en firebase debemos acceder a la consola de firebase desde la siguiente url:
Debemos estar logeados con nuestra cuenta de google, si no tienes cuanta de google tendrás que crearte una.
Para acceder a la consola seleccionamos la opción «IR A LA CONSOLA» que se encuentra en la parte superior derecha como se muestra en la siguiente imagen.
Una vez en la consola debemos añadir un nuevo proyecto, por lo tanto seleccionamos añadir proyecto y nos saldrá una ventana para introducir el nombre del proyecto y la región:
En este caso he puesto como nombre Mis Sitios y como región España.
Pulsamos el botón CREAR PROYECTO y accederemos al panel de nuestra aplicación donde tememos varias opciones.
Dejamos abierta la pestaña del navegador con el panel de firebase ya que mas tarde tenemos que volver para obtener los datos de configuración, pero ahora vamos a volver a nuestra aplicación Mis Sitiosy vamos a instalar firebase y angularfire2.
Abrimos una consola y nos situamos dentro del directorio de nuestra aplicación y escribimos el siguiente comando:
npm install angularfire2 firebase --save
Ahora editamos el archivo app.module.ts e importamos los y declaramos los módulos AngularFireModule, AngularFireDatabaseModule y AngularFireAuthModule, también declaramos la constante firebaseConfig que utilizamos en la declaración AngularFireModule.initializeApp(firebaseConfig) :
import{ BrowserModule } from '@angular/platform-browser';import{ ErrorHandler, NgModule } from '@angular/core';import{ IonicApp, IonicErrorHandler, IonicModule } from 'ionic-angular';import{ SplashScreen } from '@ionic-native/splash-screen';import{ StatusBar } from '@ionic-native/status-bar';import{ MyApp } from './app.component';import{ Geolocation } from '@ionic-native/geolocation';import{ Camera } from '@ionic-native/camera';import{ DbProvider } from '../providers/db/db';import{ SQLite } from '@ionic-native/sqlite';import{ LaunchNavigator } from '@ionic-native/launch-navigator';import{ AuthProvider } from '../providers/auth/auth';import{ AngularFireModule } from 'angularfire2';import{ AngularFireDatabaseModule } from 'angularfire2/database';import{ AngularFireAuthModule } from 'angularfire2/auth';exportconst firebaseConfig ={apiKey:"xxxxxxxxxx",authDomain:"your-domain-name.firebaseapp.com",databaseURL:"https://your-domain-name.firebaseio.com",storageBucket:"your-domain-name.appspot.com",messagingSenderId:'<your-messaging-sender-id>'};@NgModule({declarations:[
MyApp
],imports:[
BrowserModule,
IonicModule.forRoot(MyApp),AngularFireModule.initializeApp(firebaseConfig),
AngularFireDatabaseModule,
AngularFireAuthModule],bootstrap:[IonicApp],entryComponents:[
MyApp
],providers:[
StatusBar,
SplashScreen,{provide: ErrorHandler,useClass: IonicErrorHandler},
Geolocation,
Camera,
DbProvider,
SQLite,
LaunchNavigator,
AuthProvider
]})exportclass AppModule {}
Los valores que hemos puesto en el objeto firebaseConfig son provisionales, ahora debemos sustituirlos por los que nos de la consola de Firebase por lo tanto regresamos a la web de Firebase.
Aunque nuestra aplicación es una aplicación para móviles estamos utilizando tecnologías web para su desarrollo ya que no es una app nativa sino híbrida (revisar el primer post de este tutorial para saber más sobre tipo de aplicaciones), por lo tanto vamos a seleccionar Añade Firebase a tu aplicación web para ver las variables de configuración que luego vamos a necesitar:
Al seleccionar añade Firebase a tu aplicación web mostrará algo como esto:
Por lo tanto en nuestro archivo app.module.ts sustituimos los valores de apiKey, authDomain, databaseURL, projectId, storageBucket y messagingSenderId del objeto firebaseConfig por los que nos ha generado.
Una vez copiado los valores cerramos la ventana.
Firebase nos da diferentes métodos para registrar usuarios:
Correo electrónico/contraseña
Teléfono
Google
Facebook
Twitter
GitHub
Anónimo
Para este ejemplo vamos a utilizar el método Correo electrónico/contraseña.
El panel de la izquierda de nuestro proyecto en firebase seleccionamos «Authentication» y «METODO DE INICIO DE SESIÓN«, y hacemos click en Correo electrónico/contraseña como muestro en la siguiente imagen:
El la ventana que nos muestra habilitamos y le damos a Guardar:
Bien, ya tenemos configurado el método de registro de usuarios en firebase.
Ahora lo primero que necesitamos es un provider que utilizaremos para autenticar usuarios.
Por lo tanto abrimos una consola escribimos el siguiente comando que ya conocemos para crear un provider:
ionic g provider auth
En el provider que acabamos de crear eliminamos los imports de Http y rxjs/add/operator/map ya que no los vamos a necesitar, e importamos AngularFireAuth y firebase:
import{ Injectable } from '@angular/core';import{ AngularFireAuth } from 'angularfire2/auth';import* as firebase from 'firebase/app';/* Generated class for the AuthProvider provider. See https://angular.io/docs/ts/latest/guide/dependency-injection.html for more info on providers and Angular DI.*/@Injectable()exportclass AuthProvider {
constructor(privateafAuth : AngularFireAuth){
console.log('Hello AuthProvider Provider');}}
Ahora vamos a crear una nueva página de login para que el usuario pueda darse de alta y autenticarse, para ello desde la consola escribimos el siguiente comando:
ionic g page login
Esto nos habrá generado una nueva página llamada login, vamos a editar el archivo login.html para crear un formulario para autenticar y/o dar de alta a un usuario:
<!-- Generated template for the LoginPage page. See http://ionicframework.com/docs/components/#navigation for more info on Ionic pages and navigation.--><ion-header><ion-navbar><ion-title>login</ion-title></ion-navbar></ion-header><ion-content><ion-list><form><ion-item><ion-label floating>Email</ion-label><ion-input [(ngModel)]="user.email"name="email"type="text" autocapitalize="off"required></ion-input></ion-item><ion-item><ion-label floating>Contraseña</ion-label><ion-input [(ngModel)]="user.password"name="password"type="password"required></ion-input></ion-item><div padding><button ion-button (click)="login()"type="submit"color="primary" block>
Login
</button><button ion-button (click)="signin()"type="submit"color="secondary" block>
Dar de alta
</button></div></form></ion-list></ion-content>
Para simplificar vamos a utilizar el mismo formulario tanto para dar de alta a un usuario como para autenticarnos.
Como podemos ver tenemos un formulario con dos inputs, uno para el email y otro para la contraseña.
Al label de los inputs le decimos que sea de tipo floating, esto produce un efecto de desplazamiento del label al situarnos en el campo. Para saber más sobre el elemento ion-input y sus posibilidades podéis consultar el componente ion-input en la documentación oficial de ionic.
Tendremos una variable miembro llamada user que es un objeto que va a contener el email y la contraseña del usuario, si os fijáis en el campo email hacemos un data binding con [(ngModel)]= «user.email», lo mismo en el campo password con [(ngModel)]=»user.password».
Por lo tanto los cambios que hagamos en estos campos serán reflejados automáticamente en user.email y user.password.
Lo primero que haremos va a ser definir la variable user en el controlador. Abrimos el archivo login.ts y añadimos lo siguiente:
import{ Component } from '@angular/core';import{ IonicPage, NavController, NavParams } from 'ionic-angular';/** * Generated class for the LoginPage page. * * See http://ionicframework.com/docs/components/#navigation for more info * on Ionic pages and navigation.*/@IonicPage()@Component({selector:'page-login',templateUrl:'login.html',})exportclass LoginPage {user={email :'',password :''};
constructor(publicnavCtrl: NavController,publicnavParams: NavParams){}
ionViewDidLoad(){
console.log('ionViewDidLoad LoginPage');}}
En el formulario tenemos dos botones, uno para dar hacer login y otro para darnos de alta.
Como todavía no tenemos ningún usuario creado lo primero que vamos ha hacer es el alta de usuario.
Lo primero que necesitamos hacer es crear en el provider authProvider una función para dar de alta a usuarios. Editamos el archivo auth.ts y añadimos la función registerUser:
// Registro de usuario
registerUser(email:string,password:string){returnthis.afAuth.auth.createUserWithEmailAndPassword( email, password).then((res)=>{
// El usuario se ha creado correctamente.
}).catch(err=>Promise.reject(err))}
Como podemos observar mediante el método createUserWithEmailAndPassword pasándole como parámetros el email y password creamos un nuevo usuario.
Si nos fijamos el botón «Dar de alta» de nuestra página de login tiene asignado al evento click la función signin().
Por lo tanto vamos a definir la función signin en el controlador, para ello debemos importar también el provider AuthProvider que hemos creado anteriormente, también vamos a importar AlertController para mostrar los mensajes de error:
import{ Component } from '@angular/core';import{ IonicPage, NavController, NavParams,AlertController} from 'ionic-angular';import{ AuthProvider } from '../../providers/auth/auth';/** * Generated class for the LoginPage page. * * See http://ionicframework.com/docs/components/#navigation for more info * on Ionic pages and navigation.*/@IonicPage()@Component({selector:'page-login',templateUrl:'login.html',})exportclass LoginPage {
user ={email :'',password :''};
constructor(publicnavCtrl: NavController,publicnavParams: NavParams,publicauth : AuthProvider,publicalertCtrl : AlertController){}
ionViewDidLoad(){
console.log('ionViewDidLoad LoginPage');}
signin(){this.auth.registerUser(this.user.email,this.user.password).then((user)=>{// El usuario se ha creado correctamente}).catch(err=>{
let alert =this.alertCtrl.create({
title:'Error',
subTitle: err.message,
buttons:['Aceptar']});
alert.present();})}}
Como vemos en la función signin() llamamos al método registerUser que hemos creado anteriormente en el provider authProvider pasándole como parametros el email y la contraseña que las tenemos en this.user.email y this.user.password respectivamente.
Si se ha producido un error mostramos un alert con el mensaje de error que hayamos recibido.
Bien para que salga la página de login al iniciar la aplicación tenemos que cambiar el root de nuestra aplicación tal y como vimos en este post. Para ello vamos editamos el archivo app.components.ts y sustituimos:
rootPage:any ='MisTabsPage';
Por:
rootPage:any ='LoginPage';
En este momento ya podemos probar la creación de un usuario.
Ejecutamos la aplicación en el terminal, si al ejecutar os muestra un error como este:
Error:./node_modules/firebase/utils/promise.js
Module not found: Error: Can't resolve 'promise-polyfill'
Lo resolvemos instalando lo siguiente:
npm install promise-polyfill --save-exact
Una vez funcionando nuestra app aparecerá la página de login que hemos creado con el formulario para introducir usuario y contraseña. Si vamos al panel de firebase y seleccionamos Authentication y la pestaña USUARIOS veremos algo como esto:
Como podemos ver aún no hay ningún usuario creado, podríamos crear uno desde el propio panel de firebase pulsando el botón añadir usuario, pero lo que nos interesa es crearlos directamente desde nuestra aplicación.
Al ejecutar nuestra aplicación ahora mostrará la pagina de login que hemos creado con el formulario para introducir el email y la contraseña:
Si introducimos una dirección de correo y una contraseña y pulsamos el botón «Dar de alta» al refrescar la pantalla de firebase ahora veréis el usuario que acabáis de crear en el panel.
Ahora que ya podemos crear usuarios tenemos que autenticarlos y una vez autenticados tenemos que cambiar la página activa por la página misTabsPage.
Vayamos por partes.
Lo primero que necesitamos es crear en authProvider un método para autenticarnos con Correo electrónico / Contraseña, por lo tanto editamos auth.ts y añadimos el siguiente método:
// Login de usuario
loginUser(email:string,password:string){returnthis.afAuth.auth.signInWithEmailAndPassword(email, password).then(user=>Promise.resolve(user)).catch(err=>Promise.reject(err))}
Con el método signInWithEmailAndPassword(email, password) nos autenticamos en firebase, si todo va bien nos devolverá el usuario, si ha habido algo incorrecto nos devolverá un error.
Ahora en login.ts vamos a crear el método login() que se llama al pulsar el botón Login:
login(){this.auth.loginUser(this.user.email,this.user.password ).then((user)=>{}).catch(err=>{
let alert =this.alertCtrl.create({
title:'Error',
subTitle: err.message,
buttons:['Aceptar']});
alert.present();})}
Como vemos lo que hace login es llamar a la función loginUser de authProvider pasandole el email y la contraseña.
Ahora vamos a necesitar un método que nos devuelva la sesión, editamos auth.ts y añadimos la siguiente función:
// Devuelve la sessionget Session(){returnthis.afAuth.authState;}
Si no estas familiarizado con TypeScript puede que pienses que hay un error ya que entre get y Session() hay un espacio. Esta es una peculiaridad de TypeScript que nos permite hacer getters y setters de esta manera. Para obtener la sesión en lugar de llamar a la función simplemente llamamos a Session como si fuese un atributo de la clase, es decir sin el get y sin paréntesis de esta manera: this.auth.Session.subscribe(…), en este caso usamos subscribe porque Session devuelve this.afAuth.authState que a su vez devuelve un observable.
Ahora vamos a comprobar la sesión en el evento platform.ready de app.components.ts que se ejecuta cuando la app está cardada y lista y si estamos autenticados haremos que la página activa sea misTabsPage, pero si la sesión no está activa la página que se muestre se la de login.
Editamos app.components.ts y añadimos lo siguiente:
import{ Component } from '@angular/core';import{ Platform } from 'ionic-angular';import{ StatusBar } from '@ionic-native/status-bar';import{ SplashScreen } from '@ionic-native/splash-screen';import{ DbProvider } from '../providers/db/db';import{ AuthProvider } from '../providers/auth/auth';@Component({templateUrl:'app.html'})exportclass MyApp {rootPage:any='LoginPage';
constructor(platform: Platform,statusBar: StatusBar,splashScreen: SplashScreen,publicdb: DbProvider,privateauth: AuthProvider){
platform.ready().then(()=>{// Okay, so the platform is ready and our plugins are available.// Here you can do any higher level native things you might need.this.auth.Session.subscribe(session=>{if(session){this.rootPage ='MisTabsPage';}else{this.rootPage ='LoginPage';}});
statusBar.styleDefault();
splashScreen.hide();this.db.openDb().then(()=>this.db.createTableSitios())});}}
Tenemos que importar e inyectar en el constructor nuestro provider AuthProvider.
Después en patform.ready nos suscribimos a Session que como he explicado es un getter que nos devuelve un observable, si hay un cambio en la sesión automáticamente cambiara rootPage para mostrar la página de login o las pestañas en función de si tenemos la sesión activa o no.
También vamos a necesitar un método para cerrar sesión (logout), por lo tanto editamos auth.ts y añadimos el método logout:
// Logout de usuario
logout(){this.afAuth.auth.signOut().then(()=>{// hemos salido})}
Por simplificar vamos a colocar un botón de cerrar sesión en la página info que no la estamos utilizando para nada, abrimos info.html y añadimos el siguiente código:
<!-- Generated template for the InfoPage page. See http://ionicframework.com/docs/components/#navigation for more info on Ionic pages and navigation.--><ion-header><ion-navbar><ion-title>Info</ion-title></ion-navbar></ion-header><ion-content padding><button ion-button block (click)="cerrarSesion()">Cerrar Sesión</button></ion-content>
Simplemente hemos añadido un botón que al hacer click llamara a la función cerrarSession().
Vamos ahora a definir la función cerrarSesion en el controlador, abrimos info.ts y añadimos el siguiente código:
import{ Component } from '@angular/core';import{ IonicPage, NavController, NavParams } from 'ionic-angular';import{ AuthProvider } from '../../providers/auth/auth';/** * Generated class for the InfoPage page. * * See http://ionicframework.com/docs/components/#navigation for more info * on Ionic pages and navigation.*/@IonicPage()@Component({selector:'page-info',templateUrl:'info.html',})exportclass InfoPage {
constructor(publicnavCtrl: NavController,publicnavParams: NavParams,publicauth : AuthProvider){}
ionViewDidLoad(){
console.log('ionViewDidLoad InfoPage');}cerrarSesion(){this.auth.logout();}}
Simplemente importamos el provider AuthProvider, lo inyectamos en el constructor y en la función cerrarSesion llamamos al método logout del provider que acabamos de crear.
Si probamos ahora nuestra aplicación y accedemos a la pestaña info, al pulsar sobre el botón cerrar sesión nos mostrará de nuevo la página de login. Esto ocurre como ya he explicado porque en app.components.ts estamos «escuchando» a la variable Session que es un observable, al cerrar la sesión automáticamente cambia rootPage por ‘LoginPage’.
Para que no queden dudas de como debe quedar el provider AuthProvider muestro a continuación como debe de quedar el código completo del archivo auth.ts:
import{ Injectable } from '@angular/core';import{ AngularFireAuth } from 'angularfire2/auth';import* as firebase from 'firebase/app';/* Generated class for the AuthProvider provider. See https://angular.io/docs/ts/latest/guide/dependency-injection.html for more info on providers and Angular DI.*/@Injectable()exportclass AuthProvider {
constructor(privateafAuth : AngularFireAuth){
console.log('Hello AuthProvider Provider');}// Registro de usuario
registerUser(email:string,password:string){returnthis.afAuth.auth.createUserWithEmailAndPassword( email, password).then((res)=>{this.afAuth.auth.signInWithEmailAndPassword(email, password)}).then(user=>Promise.resolve(user)).catch(err=>Promise.reject(err))}// Login de usuario
loginUser(email:string,password:string){returnthis.afAuth.auth.signInWithEmailAndPassword(email, password).then(user=>Promise.resolve(user)).catch(err=>Promise.reject(err))}// Logout de usuario
logout(){this.afAuth.auth.signOut().then(()=>{// hemos salido})}// Devuelve la sessionget Session(){returnthis.afAuth.authState;}}
Eso es todo por hoy.
Hoy hemos aprendido a crear usuario y autenticarnos mediante correo electronico y contraseña en firebase. El el próximo post aprenderemos a guardar nuestros sitios en la base de datos de firebase.