Las vistas de aplicaciones nativas (iOS, Android) tienen un ciclo de vida bien estructurado que permite realizar acciones en momentos clave de su ejecución. Ionic 2 cuenta con una característica equivalente: Los lifecycle events de navegación.
En Ionic 2, cualquier vista que se añade o quita a un NavController
emite ciertos eventos que puedes aprovechar para inicializar la vista, refrescar contenido o guardar datos, por ejemplo.
Enseguida descubrirás como usarlos gracias a un ejemplo hands-on code, pero primero… ¡vamos a profundizar en el tema!
Lifecycle events
Los eventos de navegación de Ionic 2 son muy similares a los que define iOS. Aquí tienes un diagrama que muestra como funcionan.
Resumiendo, los eventos son estos:
ionViewDidLoad
: Se llama únicamente cuando cargas una página en memoria (push). Este evento NO se lanza si entras por segunda vez en una vista que ya está cacheada. Es un buen sitio para tareas relacionadas con la inicialización de la vista.-
ionViewWillEnter
: Se ejecuta cuando entras en una página, antes de cargarla. Utilízalo para tareas que se deben realizar siempre que entras en la vista, exista ya o no (activar listeners de eventos, actualizar una tabla, etc). -
ionViewDidEnter
: Se ejecuta cuando entras en una página, después de cargarla. Ahora ésta es la página activa. Muy similar a la anterior. -
ionViewWillLeave
: Se ejecuta cuando sales de una página, justo antes de salir. Utilízalo para esa lógica que necesitas siempre que sales de la vista (desactivar listeners, etc). -
ionViewDidLeave
: Se ejecuta cuando sales de una página, al acabar de salir. Ahora ésta ya no es la página activa. Muy similar a la anterior. -
ionViewWillUnload
: Se ejecuta cuando vas a destruir por completo una página (al hacer pop).
Nav guards
Como bonus track hay 2 métodos muy potentes relacionados con estos eventos, que te facilitan el control de acceso a vistas que necesitan autenticación (por ejemplo).
ionViewCanEnter
: Se ejecuta antes de entrar en una vista y te permite controlar si realmente puedes entrar en la vista o no (devolviendo true o false).-
ionViewCanLeave
: Se ejecuta antes de salir de una vista y te permite controlar si realmente puedes salir de la vista o no.
Es importante destacar que los Nav Guards se ejecutan los primeros, antes que cualquier función del lifecycle event.
Hands-on code!
Reproductor de musica ambiental
Todo se entiende mejor al ponerlo en práctica, así que te traigo un ejemplo divertido: Un reproductor de música ambiental.
Puedes bajarte el proyecto desde el siguiente enlace:
Es un ejemplo muy simple donde hay una app con 3 vistas:
- La vista Home permite escoger un ambiente sonoro
- La vista Music reproduce audio ligado a ese ambiente. Ya te avanzo que aquí es donde necesitarás usar los lifecycle events.
- La vista Credits, a la que se accede desde Music, muestra información de la app
Es decir, el flujo de navegación de las vistas es el siguiente:
La vista Music reproducirá música según el ambiente seleccionado. La reproducción de música corre a cargo de howler.js.
Vista Home
La vista principal es muy simple: Muestra una lista de botones para acceder a los distintos ambientes, con una imagen de fondo y un texto. Todo esto aderezado con un poquito de SaSS para ponerlo bonito.
El template de esta vista no tiene nada especial, solo destacar que para pasar a cada ambiente se llama al método goToMusicPage()
del propio componente, pasando como argumento el nombre del ambiente.
home.html
<ion-header>
<ion-navbar>
<ion-title>Relax yourself v0.1</ion-title>
</ion-navbar>
</ion-header>
<ion-content>
<div class="imageBtn" (click)="goToMusicPage('ocean-waves')">
<div class="image" style="background-image:url('assets/img/ocean-waves.jpg');"></div>
<div class="label">Ocean Waves</div>
</div>
<!-- ...some more DIVs like this ...-->
</ion-content>
Puedes ver la navegación que hace goToMusicPage
en el código del componente:
home.ts
import { Component } from '@angular/core';
import { NavController } from 'ionic-angular';
import { MusicPage } from '../music/music';
@Component({
selector: 'page-home',
templateUrl: 'home.html'
})
export class HomePage {
constructor(public navCtrl: NavController) {}
goToMusicPage(audio){
this.navCtrl.push(MusicPage, {audio});
}
}
Vista Music
La vista Music es aún más simple. Solo muestra una imagen relacionada con el ambiente y un botón en el header para ir a la vista Credits.
Eso sí, en esta vista oyes música.
Lo único destacable del template de Music es la navegación a Credits con la directiva navPush
.
music.html
<ion-header>
<ion-navbar>
<ion-title>Playing...</ion-title>
<ion-buttons end>
<button ion-button icon-only [navPush]="creditsPage">
<ion-icon name="information-circle"></ion-icon>
</button>
</ion-buttons>
</ion-navbar>
</ion-header>
<ion-content>
<div [style.backgroundImage]="'url(' + image +')'"></div>
</ion-content>
Si no reprodujera audio, el componente Music sería muy simple:
music.ts
import { Component } from '@angular/core';
import { NavController, NavParams } from 'ionic-angular';
import { CreditsPage } from '../credits/credits';
import * as howler from 'howler';
@Component({
selector: 'page-music',
templateUrl: 'music.html'
})
export class MusicPage {
music:any;
image:string;
creditsPage:any;
constructor(public navCtrl: NavController, public params: NavParams) {
this.creditsPage = CreditsPage;
}
/* lifecycle events */
//TODO: add lifecycle events to load, play, pause and stop audio
/* end lifecycle events */
}
Pero como ves, necesito usar los eventos de lifecycle para gestionar la carga y reproducción del audio.
ionViewDidLoad
Cuando cargo un ambiente musical (push), necesito meter en memoria el audio correspondiente, pero sin hacerlo varias veces. Por eso utilizo ionViewDidLoad
.
Como ves recibo el nombre del ambiente por parámetro y lo uso para obtener la imagen de fondo y cargar el audio correspondiente.
export class MusicPage {
/* ...some stuff ...*/
/* lifecycle events */
ionViewDidLoad() {
let audioFile = this.params.get('audio');
this.music = new howler.Howl({ src: [`assets/music/${audioFile}.mp3`]});
this.image = `assets/img/${audioFile}.jpg`;
}
//TODO: add lifecycle events to play, pause and stop audio
/* end lifecycle events */
}
ionViewWillEnter
Cada vez que Music
pasa a ser la vista activa hay que reproducir su audio ambiente. Esto lo hago en ionViewWillEnter
porque si lo hiciera en el evento anterior, no se ejecutaría al volver de la vista Credits.
Nota: ionViewWillLeave
también serviría)
export class MusicPage {
/* ...some stuff ...*/
/* lifecycle events */
ionViewDidLoad() {/*...*/}
ionViewWillEnter(){
this.music.play();
this.music.loop(true);
}
//TODO: add lifecycle events to pause and stop audio
/* end lifecycle events */
}
ionViewDidLeave
Cada vez que Music
deja de ser la vista activa hay que pausar su audio ambiente. Uso ionViewDidLeave
para que funcione también al navegar a Credits.
Nota: ionViewWillLeave
también serviría.
export class MusicPage {
/* ...some stuff ...*/
/* lifecycle events */
ionViewDidLoad() {/*...*/}
ionViewWillEnter() {/*...*/}
ionViewDidLeave(){
this.music.pause();
}
//TODO: add lifecycle events to stop audio
/* end lifecycle events */
}
ionViewWillUnload
Finalmente, quiero asegurarme de que al volver a Home, antes de destruir la vista Music he parado la música. Para eso utilizo ionViewWillUnload
.
export class MusicPage {
/* ...some stuff ...*/
/* lifecycle events */
ionViewDidLoad() {/*...*/}
ionViewWillEnter() {/*...*/}
ionViewDidLeave() {/*...*/}
ionViewWillUnload() {
this.music.stop();
this.music = null;
}
/* end lifecycle events */
}
Vista Credits
La vista Credits es solo una excusa para mostrarte la utilidad de los eventos anteriores. Es tan simple que no te enseño ni el código, con una captura bastará 😉
Resultados
Aquí tienes un vídeo con el resultado. Acuérdate de subir el sonido, sino no tiene gracia 😉
Si tienes alguna duda o comentario, házmelo saber aquí abajo 😉