Archivo de la etiqueta: ionic 5

Tutorial de IONIC: Formularios reactivos

Hola a todos, hoy vamos a hablar de los formularios reactivos.

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

En la aplicaci贸n de acertar n煤meros utilizamos [(ngModel)] para hacer Data Binding entre la vista y el controlador.

Aunque este enfoque es sencillo y es una caracter铆stica que viene heredando angular desde sus primeras versiones, en formularios complejos puede dificultar la gesti贸n de los campos, adem谩s est谩 previsto que se marque como deprecated en futuras versiones de Angular.聽

Por otro lado Angular nos ofrece los formularios reactivos que nos permite gestionar de una manera m谩s organizada聽 y escalable los campos de un formulario facilitando la validaci贸n.

Como siempre la mejor forma de comprender como funciona es con un ejemplo, as铆 que vamos a crear un nuevo proyecto al que llamaremos formulario:

ionic start formulario blank

Seleccionamos Angular como framework y para este ejemplo no es necesario integrar nuestra app con Capacitor.

El primer paso que debemos dar es importar ReactiveFormsModule en el m贸dulo de la p谩gina donde vayamos a utilizar un formulario, en este caso en home.module.ts.

import { NgModule } from '@angular/core';
import { CommonModule } from '@angular/common';
import { IonicModule } from '@ionic/angular';
import { FormsModule, ReactiveFormsModule } from '@angular/forms';
import { HomePage } from './home.page';
 
import { HomePageRoutingModule } from './home-routing.module';
 
 
@NgModule({
  imports: [
    CommonModule,
    FormsModule,
    ReactiveFormsModule,
    IonicModule,
    HomePageRoutingModule
  ],
  declarations: [HomePage]
})
export class HomePageModule {}

Crear un FormControl

Ahora en home.page.ts vamos a importar la clase FormControl y a crear una instancia para un campo que en este caso llamaremos nombre:

import { Component } from '@angular/core';
import { FormControl } from '@angular/forms';
 
@Component({
  selector: 'app-home',
  templateUrl: 'home.page.html',
  styleUrls: ['home.page.scss'],
})
export class HomePage {
 
  nombre = new FormControl('');
 
  constructor() {
  }
 
}

Vemos que al constructor FormControl le pasamos como par谩metro una cadena vac铆a (鈥樷), este es el valor inicial que tomar谩 el campo, si queremos que el campo tenga un valor de inicio podemos pasarle este valor en el constructor.

Veamos ahora c贸mo se utiliza un Form control en la plantilla, editamos el archivo home.page.html, eliminamos todo lo que hay dentro de ion-content y a帽adimos lo siguiente:

<ion-header>
  <ion-toolbar>
    <ion-title>
      Blank
    </ion-title>
  </ion-toolbar>
</ion-header>
 
<ion-content>
  <ion-item>
    <ion-label>Nombre</ion-label>
    <ion-input [formControl]="nombre"></ion-input>
  </ion-item>
</ion-content>

Simplemente en el campo ion-input indicamos que este campo va a utilizar el formControl nombre.聽

Si queremos mostrar en tiempo real el valor de nuestro campo podemos utilizar el atributo value, para verlo vamos a a帽adir una etiqueta p donde se mostrar谩 el valor de nuestro campo a medida que vamos escribiendo:

<ion-header>
  <ion-toolbar>
    <ion-title>
      Blank
    </ion-title>
  </ion-toolbar>
</ion-header>
 
<ion-content>
  <ion-item>
    <ion-label>Nombre:</ion-label>
    <ion-input [formControl]="nombre"></ion-input>
  </ion-item>
  <p class="ion-padding">{{ nombre.value }}</p>
</ion-content>

Si ejecutamos ahora nuestro proyecto al escribir algo en el campo nombre veremos como va apareciendo debajo los caracteres a medida que vamos escribiendo:

Los formularios reactivos tienen m茅todos que nos permiten cambiar el valor de un control mediante programaci贸n, lo que permite actualizar el valor sin la interacci贸n del usuario.

Por ejemplo vamos a crear un m茅todo en home.page.ts llamado cambiarNombre() que nos permita cambiar el valor del campo nombre:

cambiarNombre(){
  this.nombre.setValue('Ornitorrinco');
}

Con el m茅todo setValue asignamos el valor que deseemos al campo, en este caso el campo tomar谩 el valor 鈥極rnitorrinco鈥.

Para llamar a este m茅todo vamos a crear un bot贸n en home.page.html:

<ion-content>
  <ion-item>
    <ion-label>Nombre:</ion-label>
    <ion-input [formControl]="nombre"></ion-input>
  </ion-item>
  <p class="ion-padding">{{ nombre.value }}</p>
  <p class="ion-text-center">
    <ion-button (click)="cambiarNombre()">Cambiar nombre</ion-button>
  </p>
</ion-content>

Hemos metido el componente ion-button dentro de una etiqueta p con la clase ion-text-center para que salga centrado.

Si ejecutamos ahora nuestra aplicaci贸n veremos que al pulsar el bot贸n Cambiar nombre el campo nombre cambiar谩 su valor por la palabra Ornitorrinco.

Agrupando FormControls:聽

Los formularios generalmente contienen varios controles relacionados. Los formularios reactivos nos permiten agrupar m煤ltiples controles relacionados en un solo formulario de entrada.

FormGroup

Vamos a ver c贸mo podemos agrupar varios controles utilizando FormGroup.

Lo primero que debemos hacer es editar home.page.ts e importar FormGroup:

import { Component } from '@angular/core';
import { FormControl, FormGroup } from '@angular/forms';

Ahora en lugar de el campo nombre que ten铆amos vamos a crear una propiedad llamada usuario que ser谩 un FormGroup que contendr谩 a su vez dos instancias tipo FormControl, una para el nombre y otra para el email, quedando de la siguiente manera:

...
export class HomePage {
 
  usuario = new FormGroup({
    nombre: new FormControl(''),
    email: new FormControl(''),
  });
 
  constructor() {
  }
...

Los controles de formulario individuales ahora se recopilan dentro de un grupo.

Vamos a modificar la vista en home.page.html para ver c贸mo se utilizar un FormGroup en la plantilla:

<ion-content>
  <form [formGroup]="usuario">
    <ion-item>
      <ion-label>Nombre:</ion-label>
      <ion-input formControlName="nombre"></ion-input>
    </ion-item>
    <ion-item>
      <ion-label>Email:</ion-label>
      <ion-input formControlName="email"></ion-input>
    </ion-item>
 </form>
 <p class="ion-padding">{{ usuario.controls.nombre.value }}</p>
 <p class="ion-text-center">
   <ion-button (click)="cambiarNombre()">Cambiar nombre</ion-button>
 </p>
</ion-content>

Bien, vayamos por partes:

En primer lugar hemos a帽adido una etiqueta form a la cual mediante el par谩metro [formGroup] le indicamos que los campos del formularios van a estar asociados al FormGroup usuario que hemos creado en el controlador.

En el campo nombre ya no indicamos mediante el par谩metro [formControl] que lo asociamos con el control nombre sino que al pertenecer a un FormGroup necesitamos utilizar el par谩metro formControlName.

Hemos a帽adido otro campo para recoger el email del usuario, la estructura es identica al campo nombre, solo que como formControlName le asignamos email.

Dentro de la etiqueta p donde mostramos el contenido del campo nombre ya no podemos acceder directamente a nombre.value, ahora para acceder al valor del campo que pertenece a un FormGroup debemos especificarlo accediendo al control dentro del formgroup usuario de la siguiente manera:

<p class="ion-padding">{{ usuario.controls.nombre.value }}</p>

Si lo intentamos ejecutar nos dar谩 un error porque en el m茅todo cambiarNombre() estamos accediendo al valor del nombre directamente, debemos modificar este m茅todo en home.page.ts para que quede de la siguiente manera:

cambiarNombre(){
  this.usuario.controls.nombre.setValue('Ornitorrinco');
}

Guardar los datos del formulario:

Lo habitual es tener un un bot贸n en el formulario que al pulsarlo se procesan los datos del formulario, ya sea para enviarlos al servidor para guardarlos en una base de datos o para realizar cualquier operaci贸n con ellos.

Vamos a a帽adir ngSubmit a la etiqueta form para detectar cuando es lanzado el formulario y procesar los campos, en este caso le diremos que ejecute el m茅todo guardarDatos() que definiremos posteriormente en el controlador, por lo tanto la etiqueta form deber谩 quedar as铆:

 <form [formGroup]="usuario" (ngSubmit)="guardarDatos()">

Ahora para poder lanzar el formulario necesitamos incluir en el formulario un bot贸n de tipo submit:

<ion-content>
  <form [formGroup]="usuario" (ngSubmit)="guardarDatos()">
    <ion-item>
      <ion-label>Nombre:</ion-label>
      <ion-input formControlName="nombre"></ion-input>
    </ion-item>
    <ion-item>
      <ion-label>Email:</ion-label>
      <ion-input formControlName="email"></ion-input>
    </ion-item>
    <p class="ion-text-center">
      <ion-button type="submit">Guardar</ion-button>
    </p>  
  </form>
    <p class="ion-padding">{{ usuario.controls.nombre.value }}</p>
    <p class="ion-text-center">
      <ion-button (click)="cambiarNombre()">Cambiar nombre</ion-button>
    </p>
</ion-content>

Bien, ahora solo nos quedar铆a recoger los datos de nuestro formulario en la funci贸n guardarDatos() y hacer lo que necesitemos con ellos, en este caso simplemente vamos a mostrar en consola el contenido de los campos, por lo que en home.page.ts crearemos la funci贸n guardarDatos que quedar谩 de la siguiente forma:

 guardarDatos(){
   console.log(this.usuario.value);
 }

Si ejecutamos nuestra aplicaci贸n en el navegador, introducimos el nombre y el email y posteriormente pulsamos en el bot贸n Guardar veremos en la consola del navegador se mostrar谩 un objeto como este:

{ nombre: “Eduardo”, email: “edu.revilla.vaquero@gmail.com }

Con los datos del formulario contenidos en this.usuario.value realizaremos las operaciones que necesitemos.

Validar campos

Podemos validar los campos que introduce el usuario de una manera sencilla.

Lo primero que necesitamos es importar Validators de @angular/forms:

import { Component } from '@angular/core';
import { FormControl, FormGroup, Validators } from '@angular/forms';
...

Ahora vamos a hacer que el campo nombre sea obligatorio y que adem谩s tenga que tener como m铆nimo 4 caracteres, adem谩s vamos a hacer que se compruebe que el campo email contiene una direcci贸n de email v谩lida.

Para ello vamos a modificar los FormsControls para que queden de la siguiente manera:

usuario = new FormGroup({
  nombre: new FormControl('', [Validators.required, Validators.minLength(4)]),
  email: new FormControl('', Validators.email),
});

Como vemos al crear el FormControl nombre le pasamos como segundo par谩metro un array con dos Validators, con Validators.required indicamos que el campo es obligatorio, y con Validators.minLength(4) le estamos diciendo que el campo tiene que tener al menos 4 caracteres.

Por otro lado al crear el FormControl email le pasamos como segundo par谩metro Validators.email que har谩 una comprobaci贸n de si el campo cumple con la estructura de un email v谩lido. Como el campo email solo tiene un 煤nico validador no es necesario que est茅 contenido en un array.

Ahora vamos a hacer que el bot贸n de guardar s贸lo est茅 activo cuando se cumplan las condiciones que le hemos marcado en los validadores. Editamos home.page.html y modificamos el bot贸n de guardar para que quede de la siguiente manera:

<ion-button type="submit" [disabled]="!usuario.valid">Guardar</ion-button>

Con esto le estamos indicando que el bot贸n est茅 deshabilitado si los campos del formGroup usuario no son v谩lidos.

Si ejecutas ahora la aplicaci贸n ver谩s que debemos cumplir con los requisitos que le hemos indicado para que se active el bot贸n de guardar.

Por 煤ltimo vamos a modificar la plantilla para mostrar mensajes de error cuando no se cumplan las validaciones, editamos home.page.html y modificamos el formulario para incluir lo siguiente:

<form [formGroup]="usuario" (ngSubmit)="guardarDatos()">
    <ion-item>
      <ion-label>Nombre:</ion-label>
      <ion-input formControlName="nombre"></ion-input>
    </ion-item>
    <ion-label color="danger" *ngIf="usuario.controls.nombre.errors?.required && (usuario.touched || usuario.dirty)">* El nombre es obligatorio </ion-label>
    <ion-label color="danger" *ngIf="usuario.controls.nombre.errors?.minlength && (usuario.touched || usuario.dirty)">* El nombre tiene que tener al menos 4 caracteres.</ion-label>
    <ion-item>
      <ion-label>Email:</ion-label>
      <ion-input formControlName="email"></ion-input>
    </ion-item>
    <ion-label color="danger" *ngIf="usuario.controls.email.errors?.email && (usuario.touched || usuario.dirty)">* El email no es v谩lido.</ion-label>
    <p class="ion-text-center">
      <ion-button type="submit" [disabled]="!usuario.valid">Guardar</ion-button>
    </p>  
  </form>

En el campo nombre hemos a帽adido dos componentes ion-label. En el primero mostramos un mensaje advirtiendo que el campo nombre es obligatorio, se mostrar谩 cuando se cumpla la condici贸n que le endicamos enla directiva ngIf:

<ion-label color="danger" *ngIf="usuario.controls.nombre.errors?.required && (usuario.touched || usuario.dirty)">* El nombre es obligatorio </ion-label>

En esta directiva comprobamos primero si se ha producido el error required, es decir que el campo est茅 vac铆o.聽

Accedemos al control a trav茅s de usuario.controls.nombre, dentro de este, en errors se encuentran los tipos de errores de validaci贸n que se hayan producido, observa que hemos puesto una interrogaci贸n despu茅s de errors, esto es porque si no se ha producido ning煤n error errors valdr谩 null y dar谩 un error al intentar acceder a la propiedad required. Poniendo una interrogaci贸n solo accede a esta propiedad si existe errors.

Adem谩s hemos a帽adido otra condici贸n que se debe cumplir: (usuario.touched || usuario.dirty) esta comprobaci贸n es para聽 evitar que el validador muestre errores antes de que el usuario tenga la oportunidad de editar el formulario.

En el segundo label comprobamos que haya pasado el validador minlength, para mostrar el error de que el nombre tiene que tener al menos 4 caracteres:

<ion-label color="danger" *ngIf="usuario.controls.nombre.errors?.minlength && (usuario.touched || usuario.dirty)">* El nombre tiene que tener al menos 4 caracteres.</ion-label>

Finalmente en el campo email mostramos un error si el email no es v谩lido:

<ion-label color="danger" *ngIf="usuario.controls.email.errors?.email && (usuario.touched || usuario.dirty)">* El email no es v谩lido.</ion-label>

FormBuilder

Para facilitar la tarea de crear formularios Angular nos proporciona el servicio FormBuilder.

Para utilizar FormBuilder debemos importarlo de @angular/forms e inyectarlo en el constructor:

import { FormBuilder } from '@angular/forms';
 
鈥

 constructor(private fb: FormBuilder) {
  }

FormBuilder nos permite definir los controles del formulario en forma de array haciendo mucho m谩s c贸modo.

En home.page.ts tenemos la definici贸n del nuestro FormGroup usuario:

usuario = new FormGroup({
  nombre: new FormControl('', [Validators.required, Validators.minLength(4)]),
  email: new FormControl('', Validators.email),
});

Lo vamos a sustituir por lo siguiente:

usuario = this.fb.group({
  nombre: ['', [Validators.required, Validators.minLength(4)]],
  email: ['', Validators.email],
});

Como vemos no necesitamos llamar a new FormControl en cada control, simplemente le asignamos un array con sus propiedades, en este caso el valor por defecto que es una cadena vac铆a y los validadores.

Puede que al tener solo dos campos en este peque帽o ejemplo no le veas mucho ahorro, pero en formularios complejos con muchos campos hace que sea mucho m谩s c贸modo de definir los campos y facilita la lectura del c贸digo.

Si quieres saber m谩s sobre el desarrollo de aplicaciones con IONIC puedes adquirir mi libro, es esta entrada puedes ver el 铆ndice de contenidos del libro:

Libro: Desarrollo de aplicaciones m贸viles multiplataforma y PWAs con Ionic y Firebase desde cero.

Muchas gracias

Tutorial de IONIC: Peticiones http

Hola a todos, hoy vamos a ver c贸mo podemos comunicar una aplicaci贸n desarrollada con ionic con una API REST, para ello vamos a aprender c贸mo realizar peticiones a un servidor remoto a trav茅s de http.

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

En esta peque帽a prueba vamos acceder a una API REST para obtener desde un servidor remoto un listado de usuarios. Para este peque帽o ejemplo vamos a utilizar RANDOM USER GENERATOR que como se indica en su web es una API libre de c贸digo abierto para generar datos de usuario aleatorios para realizar pruebas. C贸mo Lorem Ipsum, pero con personas.

Lo que vamos a hacer es simplemente realizar una llamada a esta API donde recibiremos como respuesta un listado de usuarios que mostraremos en nuestra vista.

Antes de nada vamos a crear una nueva aplicaci贸n de prueba:

ionic start pruebahttp1 blank

Seleccionamos Angular como framework pulsando enter y le podemos decir que no queremos integrarlo con Capacitor, si deseas probarlo desde un dispositivo m贸vil entonces le diremos que s铆, aunque puedes integrarlo despu茅s si lo deseas.

Una vez generado el proyecto como siempre desde el terminal con cd pruebahttp1 entramos dentro de la carpeta que acabamos de crear.

Ahora vamos a crear un servicio donde gestionaremos la comunicaci贸n con el servidor remoto:

ionic g service services/http

Se habr谩 creado una carpeta services y dentro聽 un archivo .ts con el nombre http.service.ts.

Por defecto contendr谩 el siguiente c贸digo:

import { Injectable } from '@angular/core';
 
@Injectable({
 providedIn: 'root'
})
export class HttpService {
 
 constructor() { }
}

Para realizar las peticiones al servidor vamos a utilizar un paquete de angular llamado HttpClient, as铆 que vamos a importarlo en nuestro servicio:

import { Injectable } from '@angular/core';
import { HttpClient } from '@angular/common/http';

@Injectable({
  providedIn: 'root'
})
export class HttpService {

  constructor(public http: HttpClient) { }
}

Ahora debemos importar y declarar como provider en app.module.ts el servicio que acabamos de crear, tambi茅n debemos importar y declarar en los imports HttpClientModule:

import { NgModule } from '@angular/core';
import { BrowserModule } from '@angular/platform-browser';
import { RouteReuseStrategy } from '@angular/router';

import { IonicModule, IonicRouteStrategy } from '@ionic/angular';
import { SplashScreen } from '@ionic-native/splash-screen/ngx';
import { StatusBar } from '@ionic-native/status-bar/ngx';

import { AppComponent } from './app.component';
import { AppRoutingModule } from './app-routing.module';

import { HttpService } from './services/http.service';
import { HttpClientModule } from '@angular/common/http';


@NgModule({
  declarations: [AppComponent],
  entryComponents: [],
  imports: [
    BrowserModule,
    IonicModule.forRoot(),
    AppRoutingModule,
    HttpClientModule
  ],
  providers: [
    StatusBar,
    SplashScreen,
    { provide: RouteReuseStrategy, useClass: IonicRouteStrategy },
    HttpService,
  ],
  bootstrap: [AppComponent]
})
export class AppModule {}

http.get

Vamos a a帽adir un m茅todo que llamaremos loadUsers a nuestro servicio para obtener la lista de usuarios desde el servidor, por lo tanto editamos el archivo http.service.ts y a帽adimos el siguiente funci贸n despu茅s del constructor:

 loadUsers() {
   return this.http
   .get('https://randomuser.me/api/?results=25')
 }

聽En este caso llamamos a randomuser y le decimos que devuelva 25 resultados (?results=25).

http.get devuelve el resultado de la solicitud en forma de un observable.

Como resultado de la petici贸n obtendremos un JSON con un formato parecido a este:

{
聽"results":[
聽聽聽{
聽聽聽聽聽"gender":"male",
聽聽聽聽聽"name":{"title":"mr","first":"denis","last":"vieira"},
     "location":{
聽聽聽聽聽聽聽"street":"666 rua sete de setembro ",
聽聽聽聽聽聽聽"city":"rondon贸polis",
聽聽聽聽聽聽聽"state":"minas gerais",
聽聽聽聽聽聽聽"postcode":44819,
聽聽聽聽聽聽聽"coordinates":{"latitude":"-73.8339","longitude":"-19.7138"},
       "timezone":{"offset":"-2:00","description":"Mid-Atlantic"}
     },
     "email":"denis.vieira@example.com",
     "login":{
聽聽聽聽聽聽聽"uuid":"4f51bc76-8f49-4043-841d-7b2978bd7665",
聽聽聽聽聽聽聽"username":"beautifulswan509",
聽聽聽聽聽聽聽"password":"down",
聽聽聽聽聽聽聽"salt":"I9rLbtmc",
聽聽聽聽聽聽聽"md5":"3689e6b1cb08345ac5ab67b179358250",
聽聽聽聽聽聽聽"sha1":"4f0e8bf0fea756dbaa8f4e7e01b7c6a8de328abf",
聽聽聽聽聽聽聽"sha256":"a23a5af4e8622e69c464a2a30f608066e77aa8d36f037ecdb171d452b20e5c96"
聽聽聽聽聽},
     "dob":{"date":"1984-02-04T02:47:36Z","age":35},
     "registered":{"date":"2004-07-29T23:10:42Z","age":14},
     "phone":"(45) 7844-4365",
     "cell":"(73) 5854-2157",
     "id":{"name":"","value":null},
     "picture":{
聽聽聽聽聽聽聽"large":"https://randomuser.me/api/portraits/men/62.jpg",
聽聽聽聽聽聽聽"medium":"https://randomuser.me/api/portraits/med/men/62.jpg",
聽聽聽聽聽聽聽"thumbnail":"https://randomuser.me/api/portraits/thumb/men/62.jpg"
聽聽聽聽聽},
     "nat":"BR"
   }, ...

Ahora vamos a crear la vista en home.page.html para mostrar un bot贸n que llamar谩 a la funci贸n cargarUsuarios, y un listado de items con los usuarios que crearemos recorriendo con *ngFor el array usuarios que posteriormente vamos a crear en el controlador:

<ion-header>
 <ion-toolbar>
   <ion-title>
     Usuarios
   </ion-title>
 </ion-toolbar>
</ion-header>

<ion-content>
 <ion-list>
   <ion-item *ngFor="let usuario of usuarios">
     <ion-avatar slot="start">
       <img [src]="usuario.picture.medium">
     </ion-avatar>
     <ion-label>
     <h2>{{ usuario.name.first }}</h2>
     <p>{{ usuario.email }}</p>
   </ion-label>
   </ion-item>
 </ion-list>
 <ion-button expand="block" (click) = "cargarUsuarios()">Cargar Usuarios</ion-button>
</ion-content>

Vamos a modificar home.page.ts para obtener los datos desde el servicio y mostrarlos en la vista para ello editamos home.page.ts e importamos el service httpProvider que acabamos de crear:

import { HttpService } from '../services/http.service';

Para poder utilizarlo debemos inyectarlo en el constructor:

constructor(private http: HttpService) {}

Justo antes del constructor vamos a definir una variable miembro donde guardaremos el array de usuarios que recibamos desde el servidor:

...
export class HomePage {

聽usuarios: any[];

 constructor(private http: HttpService) {}
...

Ahora vamos a crear un m茅todo en home.page.ts que que a su vez llamar谩 al m茅todo loadUsers de nuestro provider para recibir los datos de los usuarios:

cargarUsuarios(){
  this.http.loadUsers().subscribe(
    (res: any) => {
      this.usuarios = res.results;
    },
    (error) =>{
      console.error(error);
    }
  );
}

Como podemos observar llamamos al m茅todo loadUsers que hemos definido en el servicio, pero no utilizamos then sino subscribe, esto es porque http no devuelve una promesa si no que devuelve un observable. Un observable se queda a la espera de recibir datos y nosotros nos 鈥渟uscribimos鈥 recibiendo estos datos en cuanto est茅n disponibles.

Esta cualidad se puede utilizar para suscribirnos a una url y observar si ha habido cambios, como por ejemplo si es un sitio de noticias donde se est谩n continuamente renovando.

La diferencia entre promesas y observables a groso modo es que la promesa devuelve los datos una 煤nica vez cuando estos son recibidos mientras que un observable se queda 鈥渧igilando鈥 si se han producido cambios y se ejecuta cada vez que un cambio se produce, aunque hasta que no te suscribes a un observable 茅ste no se ejecutar谩.

Si solo necesitamos recibir los datos una 煤nica vez sin necesidad de observar si se han producido cambios podemos utilizar promesas. Una promesa se ejecuta una vez que se haya resuelto la llamada y recibimos los datos en la funci贸n .then(res=>{鈥 }).

El c贸digo del provider en el archivo http.ts utilizando una promesa quedar铆a de la siguiente manera:

import { Injectable } from '@angular/core';
import { HttpClient } from '@angular/common/http';
 
 
@Injectable({
 providedIn: 'root'
})
export class HttpService {
 
 constructor(public http: HttpClient) { }
 
 loadUsers() {
   return this.http
   .get('https://randomuser.me/api/?results=25').toPromise();
 
 }
 
}

Simplemente聽 debemos a帽adir toPromise() despu茅s del get.

Ahora en home.ts solo tenemos que sustituir subscribe por then:

cargarUsuarios(){
  this.http.loadUsers().then(
    (res: any) => {
      this.usuarios = res.results;
    },
    (error) =>{
      console.error(error);
    }
  );
}

Si ejecutamos la aplicaci贸n con ionic serve y pulsamos en el bot贸n Cargar Usuarios podremos ver algo como esto:

 

Pod茅is observar como cada vez que pulsemos el bot贸n la lista de usuarios cambia ya que Random User Generator como su propio nombre indica devuelve una lista aleatoria de usuarios.

http.post

RANDOM USER GENERATOR聽 nos ha servido para aprender ha hacer una petici贸n get a una API REST para recibir datos, en este caso una lista de usuarios.

Si queremos conectarnos con un servicio que tengamos corriendo en un servidor remoto y necesitamos pasarle datos desde la aplicaci贸n para que se guarden en el servidor tenemos que usar http.post.

Vamos a imaginar que tenemos corriendo un servicio en PHP cuya url sea https://www.miservicio.com/adduser/ que est谩 programado para recibir v铆a post un nuevo usuario para guardarlo en la base de datos del servidor.

En nuestro servicio tendremos que crear una funci贸n similar a esta:

postDatos() {
  const datos = { nombre: 'Edu', email: 'edu.revilla.vaquero@gmail.com'};

  const options = {
聽聽聽聽聽headers: {
      'Content-Type': 'application/x-www-form-urlencoded'
    }
  };

  const url = 'https://www.miservicio.com/adduser/';

  return this.http.post(url, JSON.stringify(datos), options).toPromise();
}

En la variable datos聽 tenemos un objeto con los datos del usuario que queremos enviar al servidor, en este caso nombre y email.

Despu茅s definimos la variable options donde a su vez definimos las cabeceras en la variable headers, dependiendo de la configuraci贸n del servidor podr铆a necesitar par谩metros diferentes en la cabecera.

Como vemos http.post es bastante parecido a http.get, solo que como segundo par谩metro le pasamos la variable que contiene los datos que queremos enviar convertida a formato JSON con JSON.stringify(datos), como tercer par谩metro le pasamos options.

En data recibiremos la respuesta que nos de el servidor.

Vamos a ver un ejemplo de c贸mo obtendremos los datos enviados desde nuestra aplicaci贸n con un servicio desarrollado en PHP en el servidor:

<?php
聽聽header('Access-Control-Allow-Origin: *');

聽聽$postdata = file_get_contents("php://input");
聽聽if (isset($postdata)) {
聽聽聽$request = json_decode($postdata);
聽聽聽$request->recibido = 'OK';
聽聽聽echo json_encode($request);
聽聽}

?>

Por seguridad muchos sitios solo admiten peticiones que se hagan desde su propio dominio, 聽para no tener problemas de Cross-Origin en la primera l铆nea le asignamos la opci贸n header para indicarle que est谩 permitido cualquier origen:

header('Access-Control-Allow-Origin: *');

Tambi茅n hay que tener en cuenta que el navegador puede bloquear peticiones a dominios que no sean https, por lo que s铆 est谩s intentando acceder a un servidor que no tenga activado https puede que el navegador bloquee la petici贸n y te muestre un error en consola.

Si vas a hacer pruebas en un servidor local existen complementos para Chrome que evita el bloqueo de las peticiones Cross-Origin.

 

En este ejemplo tan sencillo lo 煤nico que hacemos en la siguiente l铆nea es recoger los datos que hemos enviado desde la aplicaci贸n:

$postdata = file_get_contents("php://input");

Despu茅s miramos si no est谩 vac铆o $postdata y en $request guardamos el objeto resultante al decodificar el json.

$request = json_decode($postdata);

Le a帽adimos una propiedad m谩s al objeto para indicar que hemos recibido la petici贸n:

$request->recibido = 'OK';

Por 煤ltimo simplemente sacamos un echo de $request convertido de nuevo a json.

Es decir que recibiremos como resultado en la app lo mismo que hemos enviado m谩s un campo recibido que contendr谩 la palabra 鈥極K鈥.

Evidentemente en otros lenguajes de programaci贸n del lado del servidor el c贸digo para recibir los datos ser铆a diferente, pero se escapa del prop贸sito de este libro el abordar como ser铆a en cada lenguaje.

Para probar esto podemos a帽adir un bot贸n al al home.page.ts del ejemplo anterior y que llame a una funci贸n de definiremos despu茅s en el controlador:

<ion-header>
 <ion-toolbar>
   <ion-title>
     Usuarios
   </ion-title>
 </ion-toolbar>
</ion-header>
 
<ion-content>
 <ion-list>
   <ion-item *ngFor="let usuario of usuarios">
     <ion-avatar slot="start">
       <img [src]="usuario.picture.medium">
     </ion-avatar>
     <ion-label>
     <h2>{{ usuario.name.first }}</h2>
     <p>{{ usuario.email }}</p>
   </ion-label>
   </ion-item>
 </ion-list>
 <ion-button expand="block" (click) = "cargarUsuarios()">Cargar Usuarios</ion-button>
 <ion-button expand="block" (click) = "post()">Peticion POST</ion-button>
</ion-content>

Definimos entonces la funci贸n post en home.page.ts:

post() {
    this.http.postDatos().then(res=>{
      alert(JSON.stringify(res));
    })
 }

Esta funci贸n simplemente va a realizar una llamada a la funci贸n postDatos que tendremos creada en nuestro servicio http y saca un alert del resultado obtenido convirti茅ndolo a texto utilizando el m茅todo stringify de JSON.

Si no tienes la posibilidad de tener un servidor para hacer pruebas puedes utilizar alg煤n servicio online que te permite hacer pruebas como por ejemplo http://httpbin.org, pudiendo quedar el m茅todo postDatos de nuestro servicio de la siguiente manera:

postDatos() {
   const datos = { nombre: 'Edu', email: 'edu.revilla.vaquero@gmail.com'};
 
   const options = {
聽聽聽聽聽headers: {
       'Content-Type': 'application/x-www-form-urlencoded'
     }
   };
 
   const url = 'http://httpbin.org/post';
 
   return this.http.post(url, JSON.stringify(datos), options).toPromise();
 }

Si quieres saber m谩s sobre el desarrollo de aplicaciones con IONIC puedes adquirir mi libro, es esta entrada puedes ver el 铆ndice de contenidos del libro:

Libro: Desarrollo de aplicaciones m贸viles multiplataforma y PWAs con Ionic y Firebase desde cero.

Muchas gracias

Tutorial de IONIC: Componentes personalizados

Hola a todos, en posts anteriores hemos aprendido a crear apps multiplataforma con Ionic.

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

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.

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 varias etiquetas html y otros componentes.

Para ver mejor c贸mo podemos crear nuestro propios componentes personalizados en Ionic vamos a crear un proyecto de prueba a que vamos a llamar miComponente:

ionic start ejemploTabs tabs

 

Seleccionamos Angular como framework y una vez creado el proyecto si聽 entramos en home.page.ts veremos esto:

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

@Component({
  selector: 'app-home',
  templateUrl: 'home.page.html',
  styleUrls: ['home.page.scss'],
})

export class HomePage {

  constructor() {}

}

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 p谩gina es un componente聽 que tiene el selector 鈥app-home鈥 y como plantilla utiliza el archivo home.page.html.

Si inspeccionamos el c贸digo que genera ionic en el navegador veremos que tenemos un elemento llamado ion-router-outlet que es la etiqueta principal donde se renderizan las p谩ginas, y dentro de esta tenemos una etiqueta app-home.

Tal y como hemos comentado las p谩ginas tambi茅n son componentes y para mostrar componentes en la plantilla se utiliza la etiqueta con el nombre del selector del componente que en este caso es app-home, por defecto los componentes llevan el prefijo app- por delante del nombre del componente.

Vamos a crear un sencillo componente al que vamos a llamar saluda, para ello vamos a echar mano de ionic generator, lo primero que vamos a crear es un m贸dulo para declarar nuestros componentes y poder luego invocarlos desde cualquier p谩gina donde los necesitemos.

Nos situamos dentro la carpeta de聽 nuestro proyecto en la consola de comandos y tecleamos lo siguiente:

ionic g module components

Esto nos habr谩 creado una carpeta llamada components y dentro un archivo llamado components.module.ts con el siguiente contenido:

import { NgModule } from '@angular/core';
import { CommonModule } from '@angular/common';



@NgModule({
  declarations: [],
  imports: [
    CommonModule
  ]
})
export class ComponentsModule { }

Ahora vamos a crear nuestro nuevo componente saluda:

 ionic g component components/saluda

 

Esto nos crear谩 una carpeta llamada saluda dentro de components con nuestro componente.

En la carpeta de nuestro componente tendremos un archivo .html para la plantilla, un archivo .scss para los estilos y un archivo .ts con el controlador.

Si observamos lo que contiene el archivo saluda.component.html vemos que simplemente muestra un p谩rrafo con el texto 鈥渟aluda works!鈥:

<p>
 saluda works!
</p>

Veamos ahora que tenemos en el archivo聽 saluda.component.ts:

import { Component, OnInit } from '@angular/core';
 
@Component({
 selector: 'app-saluda',
 templateUrl: './saluda.component.html',
 styleUrls: ['./saluda.component.scss'],
})
export class SaludaComponent implements OnInit {
 
 constructor() { }
 
 ngOnInit() {}
 
}

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 鈥榓pp-saluda鈥, que la ruta de la plantilla que utiliza es ./saluda.component.html 聽y la ruta de los estilos que utilizar谩 es ./saluda.component.scss.

Ahora vamos a importar SaludaComponent en el m贸dulo components.module.ts y lo vamos a declarar en la secci贸n declarations y en la secci贸n exports:

import { NgModule } from '@angular/core';
import { CommonModule } from '@angular/common';
import { SaludaComponent } from './saluda/saluda.component';
 
@NgModule({
 declarations: [SaludaComponent],
 imports: [
   CommonModule
 ],
 exports: [SaludaComponent]
})
export class ComponentsModule { }

Ahora para poder utilizar nuestro componente en cualquier p谩gina solo tenemos que importar ComponentModule en el m贸dulo de nuestra p谩gina y declararlo en los imports, por lo tanto vamos a editar home.module.ts e importar el m贸dulo ComponentsModule:

import { NgModule } from '@angular/core';
import { CommonModule } from '@angular/common';
import { IonicModule } from '@ionic/angular';
import { FormsModule } from '@angular/forms';
import { RouterModule } from '@angular/router';
import { ComponentsModule } from '../components/components.module';

import { HomePage } from './home.page';

@NgModule({
 imports: [
   CommonModule,
   FormsModule,
   IonicModule,
   ComponentsModule,
   RouterModule.forChild([
     {
       path: '',
       component: HomePage
     }
   ])
 ],
 declarations: [HomePage]
})
export class HomePageModule {}


Para mostrar nuestro componente en la p谩gina home editamos el archivo home.page.html, eliminamos todo lo que hay dentro de ion-content聽y a帽adimos la etiqueta con el componente que acabamos de crear:

<ion-header>
 <ion-toolbar>
   <ion-title>
     Ionic Blank
   </ion-title>
 </ion-toolbar>
</ion-header>
 
<ion-content>
 <div class="ion-padding">
   <app-saluda></app-saluda>
 </div>
</ion-content>

As铆 de f谩cil. Si ejecutamos nuestra app de ejemplo veremos algo similar a esto:

A nuestro componente le podemos a帽adir tambi茅n atributos personalizados.
Por ejemplo podemos pasarle un atributo nombre de esta manera:

<ion-header>
 <ion-toolbar>
   <ion-title>
     Ionic Blank
   </ion-title>
 </ion-toolbar>
</ion-header>
 
<ion-content>
 <div class="ion-padding">
   <app-saluda nombre="Eduardo"></app-saluda>
 </div>
</ion-content>

Luego en el controlador de nuestro componente (saluda.component.ts) definimos el par谩metro de entrada con el decorador Input de la siguiente manera:

import { Component, OnInit, Input } from '@angular/core';
 
@Component({
 selector: 'app-saluda',
 templateUrl: './saluda.component.html',
 styleUrls: ['./saluda.component.scss'],
})
export class SaludaComponent implements OnInit {
 
 @Input() nombre: string;
 constructor() { }
 
 ngOnInit() {}
 
}

Para poder utilizar el decorador Input debemos importarlo primero.

Ahora podemos hacer que en lugar de mostrar en pantalla 鈥saluda works!鈥 salude a la persona que recibamos en el par谩metro nombre, para ello vamos a crear una variable que llamaremos text y a la que en el constructor le daremos el valor 鈥樎ola鈥 concatenando el nombre que recibe como input:

import { Component, OnInit, Input } from '@angular/core';
 
@Component({
 selector: 'app-saluda',
 templateUrl: './saluda.component.html',
 styleUrls: ['./saluda.component.scss'],
})
export class SaludaComponent implements OnInit {
 
 @Input() nombre: string;
 text: string;
 
 constructor() {
   this.text = '隆Hola '+this.nombre+'!';
 }
 
 ngOnInit() {}
 
}

Ahora en la plantilla saluda.component.html vamos a hacer que se muestre el contenido de la variable text:

<p>
{{ text }}
</p>

Bien, si como en el ejemplo hemos pasado 鈥淓duardo鈥 al par谩metro nombre cabr铆a esperar ver en pantalla 鈥溌ola Eduardo!鈥, sin embargo comprobamos que muestra 鈥溌ola undefined!鈥, es evidente que hay algo que no est谩 funcionando.

Esto ocurre porque estamos accediendo a la variable this.nombre desde el constructor, y en el momento que se ejecuta el constructor a煤n no est谩n accesibles los par谩metros que recibimos en nuestro componente, para ello utilizamos ngOnInit que se ejecuta cuando nuestro componente se ha inicializado y tenemos acceso a los par谩metros:

import { Component, OnInit,  Input  } from '@angular/core';

@Component({
  selector: 'app-saluda',
  templateUrl: './saluda.component.html',
  styleUrls: ['./saluda.component.scss'],
})
export class SaludaComponent implements OnInit {

  @Input() nombre: string;
  text: string;

  constructor() {
  }

  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:

<p>
隆Hola {{ nombre }}!
</p>

Por 煤ltimo 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.page.ts definimos un array de usuarios:

import { Component } from '@angular/core';
 
@Component({
 selector: 'app-home',
 templateUrl: 'home.page.html',
 styleUrls: ['home.page.scss'],
})
export class HomePage {
 
 usuarios: any = [
   {
     nombre: 'Eduardo',
     edad: 41
   },
   {
     nombre: 'Pedro',
     edad: 28
   },
   {
     nombre: 'Francisco',
     edad: 34
   },
   {
     nombre: 'Maria',
     edad: 43
   }
 ];
 
 constructor() {}
 
}

Ahora en home.page.html podemos recorrer el array con *ngFor y mostrar nuestro componente saludo pas谩ndole la variable usuario.nombre:

<ion-header>
 <ion-toolbar>
   <ion-title>
     Ionic Blank
   </ion-title>
 </ion-toolbar>
</ion-header>
 
<ion-content>
 <div class="ion-padding">
   <app-saluda  *ngFor="let usuario of usuarios" [nombre]="usuario.nombre"></app-saluda>
 </div>
</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 c贸mo 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.

Puedes descargar o clonar este proyecto desde GitHub en el siguiente link:聽

Este ejemplo es muy sencillo y es solo para explicar c贸mo 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.

Puedes descargar o clonar este proyecto desde GitHub en el siguiente link:聽

https://github.com/edurevilla/libro-ionic-5-componentes-personalizados

 

Tutorial de IONIC: Navegaci贸n por Tabs

Hoy vamos a aprender c贸mo se genera una aplicaci贸n con varias p谩ginas en forma de tabs o pesta帽as y veremos c贸mo podemos navegar entre ellas, para ello vamos a crear un nuevo proyecto de ejemplo.

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

Vamos a utilizar la plantilla tabs para crear nuestra aplicaci贸n lo que nos generar谩 un proyecto con una estructura ya creada para utilizar tabs.

Desde la consola de comandos o terminal escribimos:

 ionic start ejemploTabs tabs

Como siempre elegimos Angular como framework y a la pregunta 鈥淚ntegrate your new app with Capacitor to target native iOS and Android?鈥 respondemos que No.

Al crear nuestra aplicaci贸n con la plantilla tabs nos genera por defecto tres tabs.

Nos situamos como siempre dentro de la carpeta del proyecto que acabamos de crear desde la consola, si ejecutamos el comando ionic serve -l podemos ver algo como esto:

Recuerda que al ejecutar ionic serve con el par谩metro -l te preguntar谩 si quieres instalar @ionic/lab.

Tambi茅n puedes comprobar como quedar铆a en un dispositivo m贸vil sin necesidad de instalar @ionic/lab, utilizando el inspector de Chrome (boton derecho en cualquier parte de la p谩gina y seleccionando inspeccionar),聽 y seleccionando la vista m贸vil en el panel:

Veamos ahora el c贸digo que se ha generado al iniciar el proyecto:

Lo primero que podemos observar es que que se han generado 5 carpetas dentro de src/app, una carpeta llamada explorer-container que contiene un componente que se va a utilizar en las p谩ginas de los tabs, veremos que son los componentes y c贸mo se crean m谩s adelante, despu茅s una por cada tab (tab1,tab2,y tab3) y por 煤ltimo otra llamada tabs:聽

tab1, tab2 y tab3 son p谩ginas normales como las que ya conocemos que simplemente contienen lo que queramos que se muestre en cada pesta帽a.

La p谩gina tabs es la p谩gina maestra donde vamos a mostrar los tabs con los iconos y controlar la ruta para que se muestre el contenido de la p谩gina correspondiente al tab activo.

Si vemos el contenido de la carpeta tabs podemos observar que contiene los archivos t铆picos de cualquier p谩gina en ionic, pero adem谩s contiene otro archivo llamado tabs.router.module.ts que es m贸dulo donde se define las ruta de cada tab:

Vamos antes de nada a ver como es el html para crear los tabs con sus correspondientes iconos, si abrimos en el editor el archivo tabs.page.html vemos que contiene el siguiente c贸digo:

 
<ion-tabs>
 
  <ion-tab-bar slot="bottom">
    <ion-tab-button tab="tab1">
      <ion-icon name="triangle"></ion-icon>
      <ion-label>Tab 1</ion-label>
    </ion-tab-button>
 
    <ion-tab-button tab="tab2">
      <ion-icon name="ellipse"></ion-icon>
      <ion-label>Tab 2</ion-label>
    </ion-tab-button>
 
    <ion-tab-button tab="tab3">
      <ion-icon name="square"></ion-icon>
      <ion-label>Tab 3</ion-label>
    </ion-tab-button>
  </ion-tab-bar>
 
</ion-tabs>

Es bastante intuitivo, tenemos la etiqueta ion-tabs que es el contenedor general para los tabs.

Despu茅s tenemos el componente ion-tab-bar donde definimos la barra donde se va a mostrar los iconos de los tabs, vemos que adem谩s tiene el atributo slot=”bottom”, con este atributo le estamos indicando que la barra se tiene que mostrar en la parte inferior de la pantalla.

Si queremos que los tabs se muestren en la parte superior deberemos cambiar slot=”bottom” por slot=”top”.

Por 煤ltimo definimos el bot贸n de cada tab con el componente 聽ion-tab-button que como vemos lleva el atributo tab=”tab1″ donde le indicamos el nombre del tab que se debe activar al pulsar sobre 茅l, este nombre es importante para posteriormente indicar en las rutas.

Dentro cada tab contiene un ion-icon donde indicamos que icono se debe mostrar con el atributo name, y un ion-label con el texto que queremos que se muestre en cada pesta帽a.

Si solo queremos que se muestre el icono sin ning煤n texto solo tenemos que eliminar la etiqueta ion-label.

El listado de iconos disponibles lo pod茅is consultar el la documentaci贸n oficial de ionic desde el siguiente enlace: https://ionicframework.com/docs/ionicons/

Los iconos a su vez puede tener tres estilos diferentes:

  • Outline.
  • Filled.
  • Sharp

Bien, veamos ahora el contenido del archivo tabs.routing.module.ts:

import { NgModule } from '@angular/core';
import { RouterModule, Routes } from '@angular/router';
import { TabsPage } from './tabs.page';
 
const routes: Routes = [
  {
    path: 'tabs',
    component: TabsPage,
    children: [
      {
        path: 'tab1',
        loadChildren: () => import('../tab1/tab1.module').then(m => m.Tab1PageModule)
      },
      {
        path: 'tab2',
        loadChildren: () => import('../tab2/tab2.module').then(m => m.Tab2PageModule)
      },
      {
        path: 'tab3',
        loadChildren: () => import('../tab3/tab3.module').then(m => m.Tab3PageModule)
      },
      {
        path: '',
        redirectTo: '/tabs/tab1',
        pathMatch: 'full'
      }
    ]
  },
  {
    path: '',
    redirectTo: '/tabs/tab1',
    pathMatch: 'full'
  }
];
 
@NgModule({
  imports: [RouterModule.forChild(routes)],
  exports: [RouterModule]
})
export class TabsPageRoutingModule {}

Lo interesante aqu铆 es la declaraci贸n de las rutas de los tabs:

Vemos que se declara la constante routes y dentro indicamos que el path 鈥榯abs鈥 est谩 asociado al componente TabsPage, y luego como 鈥渉ijos鈥 (children) est谩n definidos cada uno de los tabs con su ruta indicada en path y a su vez en children se carga con loadChildren el m贸dulo de la p谩gina a mostrar.聽

Puede resultar un poco engorroso, pero no debes preocuparte demasiado, el trabajo de crear las rutas ya lo hace ionic por t铆, solo debes hacer algunos cambios siguiendo esta estructura si quieres a帽adir un nuevo tab a tu proyecto, vamos a ver como se hace a continuaci贸n.

Como el contenido que se muestra en cada tab es una p谩gina, si queremos a帽adir un nuevo tab a nuestro proyecto crearemos una nueva p谩gina, por lo tanto vamos a crear una nueva p谩gina llamada tab4:

ionic g page tab4

Al crear una p谩gina nueva ionic autom谩ticamente a帽ade la ruta de la p谩gina a app-routing.module.ts, en este caso no nos interesa porque la p谩gina tab4 va a depender de la p谩gina maestra tabs y que tiene su propio m贸dulo para definir las rutas (tabs.router.module.ts), tal y como hemos visto, por lo tanto vamos a editar el archivo app-routing.module.ts y eliminamos la siguiente l铆nea que nos ha generado:

import { NgModule } from '@angular/core';
import { Routes, RouterModule } from '@angular/router';

const routes: Routes = [
 { path: '', loadChildren: './tabs/tabs.module#TabsPageModule' },
 // { path: 'tab4', loadChildren: './tab4/tab4.module#Tab4PageModule' } // debemos eliminar esta l铆nea
];
@NgModule({
 imports: [RouterModule.forRoot(routes)],
 exports: [RouterModule]
})
export class AppRoutingModule {}

Ahora vamos a definir la ruta del nuevo tab en tabs.routing.module.ts:

import { NgModule } from '@angular/core';
import { RouterModule, Routes } from '@angular/router';
import { TabsPage } from './tabs.page';
 
const routes: Routes = [
  {
    path: 'tabs',
    component: TabsPage,
    children: [
      {
        path: 'tab1',
        loadChildren: () => import('../tab1/tab1.module').then(m => m.Tab1PageModule)
      },
      {
        path: 'tab2',
        loadChildren: () => import('../tab2/tab2.module').then(m => m.Tab2PageModule)
      },
      {
        path: 'tab3',
        loadChildren: () => import('../tab3/tab3.module').then(m => m.Tab3PageModule)
      },
      {
        path: 'tab4',
        loadChildren: () => import('../tab4/tab4.module').then(m => m.Tab4PageModule)
      },
      {
        path: '',
        redirectTo: '/tabs/tab1',
        pathMatch: 'full'
      }
    ]
  },
  {
    path: '',
    redirectTo: '/tabs/tab1',
    pathMatch: 'full'
  }
];
 
@NgModule({
  imports: [RouterModule.forChild(routes)],
  exports: [RouterModule]
})
export class TabsPageRoutingModule {}
 

Simplemente hemos copiado la estructura de los otros tabs para el tab4:
... 
 {
        path: 'tab4',
        loadChildren: () => import('../tab4/tab4.module').then(m => m.Tab4PageModule)
 },

Ya solo nos queda modificar el html del archivo tabs.page.html para a帽adir el bot贸n de la nueva pesta帽a:

<ion-tabs>
 
  <ion-tab-bar slot="bottom">
    <ion-tab-button tab="tab1">
      <ion-icon name="triangle"></ion-icon>
      <ion-label>Tab 1</ion-label>
    </ion-tab-button>
 
    <ion-tab-button tab="tab2">
      <ion-icon name="ellipse"></ion-icon>
      <ion-label>Tab 2</ion-label>
    </ion-tab-button>
 
    <ion-tab-button tab="tab3">
      <ion-icon name="cube"></ion-icon>
      <ion-label>Tab 3</ion-label>
    </ion-tab-button>
 
    <ion-tab-button tab="tab4">
      <ion-icon name="alarm"></ion-icon>
      <ion-label>Tab 4</ion-label>
    </ion-tab-button>
 
  </ion-tab-bar>
 
</ion-tabs>

Ya tenemos en funcionamiento nuestra aplicaci贸n con los cuatro tabs:

Puedes descargar o clonar este proyecto desde GitHub en el siguiente link:

https://github.com/edurevilla/libro-ionic-5-tabs.git

 

Eso es todo por hoy.

Tutorial de IONIC: Navegaci贸n

Hola a todos, en el post anterior vimos聽 una app simple, un minijuego de adivinar n煤meros que nos sirvi贸 para aprender c贸mo se programa la l贸gica de una p谩gina en Ionic.

La aplicaci贸n era extremadamente sencilla y toda la l贸gica se desarrollaba en la misma p谩gina, sin embargo lo normal en cualquier aplicaci贸n que sea m铆nimamente completa es que tenga varias vistas o p谩ginas y haya que navegar entre ellas.

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

Vamos a crear un nuevo proyecto de prueba para observar c贸mo funciona la navegaci贸n entre p谩ginas en ionic.

Nos situamos en la carpeta donde queramos crear nuestro proyecto y desde consola escribimos el siguiente comando:

 ionic start navegacion blank

Seleccionamos Angular como framework y esperamos a que se termine de crear el proyecto.

Nos situamos dentro de la carpeta del proyecto que acabamos de crear:

cd navegacion

Ahora vamos a crear una nueva p谩gina para poder navegar entre dos p谩ginas, pero antes de seguir vamos a conocer Ionic Generator, una herramienta de nos ofrece Ionic para crear componentes autom谩ticamente.

Ionic Generator

Nosotros podemos crear las p谩ginas a mano creando una carpeta para nuestra p谩gina con su vista html y su controlador .ts, y su archivo de estilo .scss, tambi茅n podemos crear y configurar otros elementos a mano, pero el cli (command line interface o interfaz de l铆nea de comandos) de ionic nos facilita much铆simo el trabajo. Ionic dispone de una herramienta llamada ionic generator.

Ionic generator nos permite generar plantillas con los componentes que queramos.

Con el siguiente comando obtenemos la lista de elementos disponible que podemos generar con ionic generator:

ionic g

La lista de elementos que podemos generar autom谩ticamente con ionic generator son:

  • page: P谩ginas.
  • component: Los componentes son un conjunto de html, con su css y su comportamiento que podemos reutilizar en cualquier lugar sin tener que reescribir de nuevo todo.
  • service: Los services son proveedores que se encargan del manejo de datos, bien extra铆dos de la base de datos, desde una api, etc. En versiones anterioes a la 4 de ionic se llamaban providers.
  • module: Nos permite crear un m贸dulo.
  • class: Nos permite crear una clase.
  • directive: Una directiva sirve para modificar atributos de un elemento.
  • guard: Genera un 鈥済uardi谩n鈥 que nos permite crear una protecci贸n para permitir que los componentes solo se activen si se cumple alguna condici贸n, como por ejemplo si el usuario est谩 logueado.
  • pipe: Los pipes nos permiten crear filtros para aplicar a la informaci贸n que mostramos en la plantilla, por ejemplo podemos aplicar un filtro que convierta un texto en may煤sculas.
  • interface: Nos permite crear una interfaz.
  • enum: genera una enumeraci贸n.

Veremos con m谩s detalle cada elemento seg煤n lo vayamos necesitando, para este ejemplo de momento nos interesa聽 page as铆 que con las flechas del cursor seleccionamos page y pulsamos enter, despu茅s nos pregunta el nombre que queremos darle a la p谩gina, le llamamos por ejemplo Pagina2 y pulsamos enter.

Tambi茅n podr铆amos haber creado la p谩gina directamente escribiendo:

ionic g page Pagina2 

Est谩 es la manera que utilizaremos a partir de ahora para crear p谩ginas.

Podemos observar que en la carpeta app se ha creado una nueva carpeta llamada pagina2:

Vemos que al crear una p谩gina con ionic generator adem谩s del archivo pagina2.page.ts tambi茅n se genera un archivo pagina2.module.ts y otro pagina2-routing.module.ts en cada p谩gina generada, este archivo se utiliza para poder realizar lo que se conoce como Lazy Loading, que permite cargar p谩ginas y recursos bajo demanda acelerando as铆 la carga de las p谩ginas.

En versiones anteriores a ionic 4, utiliz谩bamos algo parecido a esto para navegar hacia una p谩gina:

this.navCtrl.push(‘miPagina’);

Aunque todav铆a se puede utilizar este sistema lo recomendable es utilizar el routing de angular basado en diferentes URL para cada p谩gina o componente a mostrar.

Si echamos un vistazo al archivo app-routing.module.ts vemos que contiene lo siguiente:

import { NgModule } from '@angular/core';
import { PreloadAllModules, RouterModule, Routes } from '@angular/router';

const routes: Routes = [
  { path: '', redirectTo: 'home', pathMatch: 'full' },
  { path: 'home', loadChildren: () => import('./home/home.module').then( m => m.HomePageModule)},
  {
    path: 'pagina2',
    loadChildren: () => import('./pagina2/pagina2.module').then( m => m.Pagina2PageModule)
  },
];

@NgModule({
  imports: [
    RouterModule.forRoot(routes, { preloadingStrategy: PreloadAllModules })
  ],
  exports: [RouterModule]
})
export class AppRoutingModule { }

C贸mo podemos observar contiene una constante llamada Routes donde se han generado autom谩ticamente las rutas a nuestras dos p谩ginas home y Pagina2.

El primer path que se define est谩 vac铆o y redirecciona a home, esto indica que home ser谩 la p谩gina por defecto cuando no se especifique ninguna.

Vemos tambi茅n que la ruta que se especifica en loadChildren de las dos p谩ginas no apunta a componente de la p谩gina si no a su m贸dulo, de esta manera se definen las rutas para hacer lazy loading.

Vamos a ver a continuaci贸n las diferentes opciones que tenemos para navegar entre p谩ginas.

Navegar entre p谩ginas utilizando routerLink en la plantilla html

Podemos utilizar routerLink directamente para indicar la ruta de la p谩gina que queremos mostrar.

Vamos a editar home.page.html, eliminamos el contenido que se genera por defecto y vamos a crear una p谩gina sencilla con un bot贸n para ir a la p谩gina 2.

<ion-header>
 <ion-toolbar>
   <ion-title>
     Ionic Blank
   </ion-title>
 </ion-toolbar>
</ion-header>
 
<ion-content>
  <div class="ion-padding">
    <ion-button routerLink="/pagina2" routerDirection="forward">Ir a la p谩gina 2</ion-button>
  </div>
</ion-content>

Ahora vamos a editar pagina2.page.html y lo dejamos de la siguiente manera:

<ion-header>
  <ion-toolbar>
    <ion-title>Pagina2</ion-title>
  </ion-toolbar>
</ion-header>

<ion-content>
  <div class="ion-padding">
    <p>Soy la p谩gina 2</p>
    <ion-button routerLink="/home" routerDirection="back">Volver a home</ion-button>
  </div>
</ion-content>

Aunque no es obligatorio podemos utilizar como en el ejemplo el par谩metro routerDirection para indicar la direcci贸n de la animaci贸n. Los valores posibles son tres: fordward, back y root, puedes hacer pruebas cambiando el valor de routerDirection para que entiendas mejor qu茅 hace cada uno.聽

Vemos que simplemente poniendo la ruta de la p谩gina dentro de href podemos navegar entre dos p谩ginas, si ejecutamos ionic serve -l veremos algo como esto:

Navegar entre p谩ginas program谩ticamente

Si bien podemos navegar entre las distintas p谩ginas de nuestra aplicaci贸n utilizando href en un bot贸n o en un 铆tem de nuestra plantilla html, a veces necesitaremos que se muestre una p谩gina desde la l贸gica del controlador.聽

Lo primero que vamos a hacer es modificar el bot贸n de la p谩gina home.page.html, en lugar de la propiedad href le vamos a asignar un evento (click) que llame a una funci贸n del controlador que vamos a llamar goToPagina2:

<ion-content>
  <div class="ion-padding">
    <ion-button (click)="goToPagina2()" routerDirection="forward">Ir a la p谩gina 2</ion-button>
  </div>
</ion-content>

Ahora vamos a editar home.page.ts para crear esta funci贸n que nos permita navegar hasta la p谩gina 2.

Aunque podr铆amos importar y utilizar el聽 Router de angular con el m茅todo navigateByUrl, este m茅todo no nos permite definir la direcci贸n de la navegaci贸n, por lo que es mejor utilizar NavController.

Lo primero que debemos hacer es importar NavController:

import { NavController } from '@ionic/angular';

Ahora debemos inyectarlo en el constructor:

constructor(private navCtrl: NavController){

}

Al inyectar un elemento en el constructor nos permite acceder a sus m茅todos desde cualquier sitio de la p谩gina.

Para finalizar vamos a crear la funci贸n goToPagina2 a la que hac铆amos referencia desde el bot贸n de la plantilla:

goToPagina2(){
  this.navCtrl.navigateForward('/pagina2');
}

Tenemos tres m茅todos que podemos utilizar para navegar seg煤n la direcci贸n al igual que lo hac铆amos cuando hemos utilizado href, estos tres m茅todos son: navigateForward, navigateBack y navigateRoot.

Una vez m谩s te animo a que experimentes con ellos para que entiendas mejor lo que hace cada uno.

El c贸digo completo de home.page.ts quedar铆a de la siguiente manera:

import { Component } from '@angular/core';
import { NavController } from '@ionic/angular';

@Component({
 selector: 'app-home',
 templateUrl: 'home.page.html',
 styleUrls: ['home.page.scss'],
})
export class HomePage {

 constructor(private navCtrl: NavController){

 }
 goToPagina2(){
   this.navCtrl.navigateForward('/Pagina2');
 }

}

Volver a la p谩gina anterior

Para volver a la p谩gina anterior podemos utilizar el componente ion-back-button en nuestra plantilla, lo podemos utilizar para poner el t铆pico bot贸n de volver en la cabecera.

Para probarlo vamos a editar el archivo pagina2.page.html y vamos a a帽adir lo siguiente en la cabecera:

<ion-header>
 <ion-toolbar>
   <ion-title>Pagina2</ion-title>
   <ion-buttons slot="start">
     <ion-back-button defaultHref="/home"></ion-back-button>
    </ion-buttons>
 </ion-toolbar>
</ion-header>

<ion-content>
  <div class="ion-padding">
    <p>Soy la p谩gina 2</p>
    <ion-button routerLink="/home" routerDirection="back">Volver a home</ion-button>
  </div>
</ion-content>

Podemos observar que hemos puesto una propiedad llamada defaultHref, con esto le estamos indicando que la ruta por defecto sea /home. Al pulsar este bot贸n vamos a navegar hacia atr谩s a la p谩gina anterior en el historial, si por alg煤n motivo no encontrase la p谩gina anterior por defecto cargar铆a home.聽

En este caso como solo tenemos dos p谩ginas coincide que la p谩gina anterior siempre va a ser home.

Por otro lado hemos creado el elemento ion-back-button dentro del contenedor ion-buttons, esto nos sirve para contener botones. Podemos observar que ion-buttons tiene un atributo llamado slot聽 al que hemos asignado el valor start. Con esto le indicamos que los botones que contenga se van a mostrar al inicio, es decir a la izquierda.

El atributo slot indica para indicar la posici贸n o el estilo que van a tener los elementos.

Existen diferentes valores que podemos utilizar con slot, como por ejemplo: item-left, end, start, icon-left, range-left, range-right, icon-only, etc, dependiendo del componente puede aceptar o no diferentes tipos de slot por lo deberemos revisar la documentaci贸n del componente para ver qu茅 posibilidades nos ofrece.

Como podemos ver si ejecutamos ionic serve ion-back-button nos ha creado un bot贸n de volver atr谩s en la cabecera:

Pasando datos entre p谩ginas

Muchas veces nos interesa pasar datos al llamar a una p谩gina.

Por ejemplo podemos tener un listado de productos y al pulsar en un producto queremos llamar a una p谩gina donde se muestre el detalle de ese producto.

Al utilizar el router de Angular debemos pasar los datos que necesitemos en la url.

Aunque podr铆amos pasar toda la informaci贸n del producto en la propia url convertido en json no es lo m谩s pr谩ctico, lo m谩s usual es pasar el id del producto y con el id utilizar un servicio para obtener los datos relacionados con el producto seleccionado. Aprenderemos m谩s adelante a crear y utilizar servicios, de momento vamos a ver c贸mo podemos pasar un id a la p谩gina a la que llamamos.

Vamos a seguir haciendo pruebas con el proyecto navegaci贸n, lo primero que vamos a hacer es editar el archivo app-routing.module.ts que es el archivo donde de definen las rutas de nuestras p谩ginas.聽

Al crear una p谩gina con ionic generator ya se crea autom谩ticamente la ruta en app-routing.module.ts , sin embargo para poder a帽adir datos a la url debemos especificar el nombre del dato que vamos a enviar, en este ejemplo queremos mandar un dato llamado id as铆 que debemos a帽adir /:id a la ruta de la p谩gina 2:

import { NgModule } from '@angular/core';
import { PreloadAllModules, RouterModule, Routes } from '@angular/router';

const routes: Routes = [
  { path: '', redirectTo: 'home', pathMatch: 'full' },
  { path: 'home', loadChildren: () => import('./home/home.module').then( m => m.HomePageModule)},
  {
    path: 'pagina2/:id',
    loadChildren: () => import('./pagina2/pagina2.module').then( m => m.Pagina2PageModule)
  },
];

@NgModule({
  imports: [
    RouterModule.forRoot(routes, { preloadingStrategy: PreloadAllModules })
  ],
  exports: [RouterModule]
})
export class AppRoutingModule { }

 

Como podemos observar hemos hemos definido la el path de la ruta de la Pagina2 como:聽 pagina2/:id 聽a帽adiendo /:id por detr谩s, as铆 despu茅s podremos hacer referencia a id desde la p谩gina 2.

Ahora vamos a pasarle por ejemplo el id 14 cuando llamamos a la p谩gina 2 desde la p谩gina Home, para ello editamos el archivo home.page.ts y modificamos la funci贸n goToPagina2() a帽adiendo el n煤mero 14 a la url:

goToPagina2(){
  this.navCtrl.navigateForward('/pagina2/14');
}

Por 煤ltimo vamos a ver c贸mo obtenemos el id en Pagina2, editamos el archivo pagina2.page.ts y lo primero que necesitamos hacer es importar ActivatedRoute para poder obtener los par谩metros recibidos en la url:

import { ActivatedRoute } from '@angular/router';

Ahora debemos inyectarlo en el constructor:

constructor(private route: ActivatedRoute) { }

Finalmente en la funci贸n ngOnInit que se ejecuta al iniciar la p谩gina recogemos el id y simplemente lo vamos a mostrar a trav茅s de un alert:

ngOnInit() {
   let id = this.route.snapshot.paramMap.get('id');
   alert(id);
 }

Para recoger el id utilizamos this.route.snapshot.paramMap.get(‘id’).

El c贸digo completo de pagina2.page.ts por lo tanto quedar铆a de la siguiente manera:

import { Component, OnInit } from '@angular/core';
import { ActivatedRoute } from '@angular/router';

@Component({
  selector: 'app-pagina2',
  templateUrl: './pagina2.page.html',
  styleUrls: ['./pagina2.page.scss'],
})
export class Pagina2Page implements OnInit {

  constructor(private route: ActivatedRoute) { }

  ngOnInit() {
    let id = this.route.snapshot.paramMap.get('id');
    alert(id);
  } 

}

Si corremos la aplicaci贸n con ionic serve veremos que al pasar a la p谩gina 2 saca un alert con el n煤mero 14.

Puedes descargar o clonar este proyecto desde GitHub en el siguiente link:

https://github.com/edurevilla/libro-ionic-navegacion

Para no hacer este post demasiado largo por hoy lo vamos a dejar aqu铆. En el pr贸ximo post veremos c贸mo utilizar men煤s laterales, navegaci贸n por tabs etc.

 

Eso es todo por hoy,聽 nos vemos en el pr贸ximo post :).

Tutorial de IONIC:Mini Juego de acertar n煤meros (actualizado)

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

Despu茅s de ver en el post anterior como modificar la plantilla de una p谩gina para simplemente mostrar el texto 鈥淗ola Mundo鈥, vamos a avanzar un poco m谩s en nuestro aprendizaje y vamos a programar nuestra primera aplicaci贸n interactiva.

Se trata de un simple juego de acertar el n煤mero secreto. La aplicaci贸n crear谩 un n煤mero aleatorio que nosotros debemos adivinar.

Por primera vez vamos a programar con Ionic. Por el camino aprenderemos conceptos como Data Binding, que nos permite actualizar valores entre el html y el controlador y recoger las acciones del usuario como聽 pulsar un bot贸n.

Bien, sin m谩s pre谩mbulos聽 vamos a empezar:

Vamos a crear un nuevo proyecto Ionic que en este caso le vamos a llamar adivina: Abrimos el terminal o consola de comandos y situ谩ndonos en la carpeta donde queremos crear nuestro proyecto escribimos:

ionic start adivina blank

 

Seleccionamos Angular como framework y esperamos a que se terminen de instalar los paquetes.

Nos situamos dentro de la carpeta del proyecto de acabamos de crear y聽una vez dentro ejecutamos ionic serve para ver en el navegador los cambios que vayamos haciendo en nuestra aplicaci贸n:

 ionic serve -l

 

Recuerda que si utilizas la opci贸n -l con ionic serve puedes visualizar como queda la app en todas las plataformas, la primera vez que ejecutes el comando en un proyecto nuevo te pedir谩 que instales @ionic/lab.

Ahora abrimos la carpeta del proyecto que acabamos de crear en el editor, entramos en src/app/home聽y abrimos el archivo home.page.html.

Editamos su contenido para que quede de la siguiente manera:

<ion-header>
  <ion-toolbar>
    <ion-title>
      Adivina el n煤mero secreto
    </ion-title>
  </ion-toolbar>
</ion-header>
 
<ion-content>
  <div class="ion-padding">
    <ion-input type="number" min="1" max="100" [(ngModel)]="num" placeholder="Introduce un n煤mero del 1 al 100"></ion-input>
    <p>El n煤mero secreto es {{ mayorMenor }} {{ num }}</p>
    <ion-button expand="block" (click)="compruebaNumero()">Adivina</ion-button>     
  </div>
</ion-content>

 

Si nunca antes has programado en angular ni en ionic es posible que el c贸digo te resulte extra帽o, no te preocupes, ahora vamos a ver lo que es cada cosa, si por el contrario ya has programado en angular o en versiones anteriores de ionic es probable este c贸digo te resulte familiar.

Tenemos una plantilla b谩sica de una p谩gina con ion-header, ion-navbar y ion-title donde hemos puesto el t铆tulo de nuestra aplicaci贸n 鈥淎divina el n煤mero secreto鈥. Hasta aqu铆 ninguna novedad con lo que ya hab铆amos visto en el cap铆tulo anterior.

Dentro de ion-content que como sabemos es donde va el contenido de la p谩gina tenemos un div al que le aplicamos la clase ion-padding que deja un espacio entre el borde de la pantalla y el contenido dentro de este div es donde est谩 lo interesante:

<ion-input type="number" min="1" max="100" [(ngModel)]="num" placeholder="Introduce un n煤mero del 1 al 100"></ion-input>


Primero tenemos un
ion-input que es muy parecido a un input de html, le decimos que sea de tipo number, le ponemos un rango m铆nimo a 1 y m谩ximo a 100.

El siguiente par谩metro [(ngModel)] es el encargado de hacer el Data Binding entre el valor del input y una variable llamada num que estar谩 definida como luego veremos en el controlador de la p谩gina. Este es un Data Binding bidireccional ya que si se introduce un valor en el input autom谩ticamente este ser谩 reflejado en la variable del controlador, del mismo modo si alg煤n proceso cambia el valor de esta variable en el controlador 茅ste autom谩ticamente aparecer谩 reflejado como valor del input.聽

Por 煤ltimo el input tiene un placeholder indicando que se introduzca un valor entre 1 y 100.

La siguiente l铆nea es un p谩rrafo que contiene lo siguiente:

聽<p>El n煤mero secreto es {{ mayorMenor }} {{ num }}</p>

Si ya conoces ionic o angular sabes de qu茅 se trata. En este caso con las dobles llaves 鈥渰{ }}鈥澛 hacemos un Data Binding unidireccional, mayorMenor es una variable que estar谩 definida en el controlador y con las dobles llaves muestra su valor.聽

La variable contendr谩 el texto 鈥渕ayor que鈥 en caso de que el n煤mero secreto sea mayor al introducido, 鈥渕enor que鈥 en caso de ser menor e 鈥渋gual a鈥 en caso de ser igual.

En las 煤ltimas llaves mostramos el valor de la variable num, veremos c贸mo al introducir un n煤mero este se actualiza autom谩ticamente.

Por 煤ltimo tenemos un bot贸n para comprobar si el n煤mero introducido coincide con el n煤mero secreto:

<ion-button expand=”block” (click)=”compruebaNumero()”>Adivina</ion-button>

En la documentaci贸n oficial de ionic pod茅is ver m谩s sobre c贸mo crear distintos tipos de botones con ionic:https://ionicframework.com/docs/api/button

De momento esto es todo lo que necesitamos en la plantilla de nuestro juego.

Ahora necesitamos programar el comportamiento en el controlador de la p谩gina.

Si abrimos el archivo home.page.ts que se genera autom谩ticamente al crear un proyecto en blanco veremos el siguiente c贸digo:

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

@Component({
  selector: 'app-home',
  templateUrl: 'home.page.html',
  styleUrls: ['home.page.scss'],
})
export class HomePage {

  constructor() {}

}

 

Este c贸digo esta es typeScript. Como ya hemos comentado TypeScript permite utilizar elementos de las 煤ltimas versiones del est谩ndar ECMAscript aunque todav铆a no est茅n implementadas en el navegador que estemos utilizando. Tambi茅n nos permite utilizar variables tipadas.

Como hemos comentado anteriormente con Ionic vamos a utilizar Angular que a su vez utiliza TypeScript, as铆 que es muy beneficioso conocer Angular y typescript.

Aqu铆 vamos a explicar a groso modo las cuestiones m谩s importantes para poder desenvolvernos con ionic pero para saber m谩s sobre Angular y sacarle el m谩ximo pod茅is encontrar en la red muchos recursos para aprender Angular.

Analicemos el c贸digo de home.page.ts:

Lo primero que vemos es una l铆nea import:

import { Component } from ‘@angular/core’;

Import se utiliza para importar m贸dulos que contienen librer铆as y clases para poder utilizarlas en nuestro proyecto. Podemos importar m贸dulos propios de Ionic que ya se incorporan al crear un proyecto, librer铆as de Angular, librer铆as de terceros que podemos instalar o nuestras propias聽 librer铆as.

En este caso se importa el elemento Component de @angular/core.

Las p谩ginas son componentes de Angular, por eso necesitamos importar Component.

Despu茅s vemos el siguiente c贸digo:

@Component({
  selector: 'app-home',
  templateUrl: 'home.page.html',
  styleUrls: ['home.page.scss'],
}) 

 

@Component es un decorador de Angular. Angular usa los decoradores para registrar un componente.

Los decoradores empiezan con @.

Los decoradores se colocan antes de la clase y definen c贸mo se va a comportar esta.

Existen los siguientes聽 decoradores:

  • @Component
  • @Injectable
  • @Pipe
  • @Directive

De momento nos interesa @Component.

En el c贸digo vemos que @Component contiene un objeto con dos atributos, selector:鈥檃pp-home鈥, que es el selector que se va a aplicar a la p谩gina,聽 templateUrl:鈥檋ome.page.html鈥 que es la plantilla html que va a renderizar la p谩gina y styleUrls: [鈥榟ome.page.scss鈥橾 donde se indica d贸nde se encuentran los estilos que se van a aplicar al componente, es decir,聽 en este caso a la p谩gina.

Por 煤ltimo se exporta una clase llamada HomePage:

export class HomePage {

  constructor() {}

}

 

Podemos a帽adir a la clase un constructor en caso de que necesitemos iniciar atributos de la clase, inyectar dependencias o realizar alguna operaci贸n en el momento de crear la clase, en este ejemplo no lo vamos a necesitar, lo veremos m谩s adelante en otros ejemplos.

En TypeScript la creaci贸n de clases es muy similar a c贸mo ser铆a en otros lenguajes de programaci贸n orientado a objetos como Java.

Todos los datos que se muestran en la plantilla y todas las funciones a las que se llame por ejemplo al hacer clic en un bot贸n deben formar parte de la clase HomePage que es el controlador de la p谩gina.

Como ya hemos visto en la plantilla home.page.html utilizamos [(ngModel)]=鈥漬um鈥 para recoger en la variable num el valor que se introduzca en el campo input, tambi茅n mostramos otra variable llamada mayorMenor que indicar谩聽 si el n煤mero introducido es mayor o menor que el n煤mero que hay que adivinar y mostramos la variable num que se actualizar谩 instant谩neamente al introducir un n煤mero.

<ion-input type="number" min="1" max="100" [(ngModel)]="num" placeholder="Introduce un n煤mero del 1 al 100"></ion-input>
<p>El n煤mero secreto es {{ mayorMenor }} {{ num }}</p>


Por lo tanto estas variables deben de estar definidas en el controlador dentro de la clase
HomePage del archivo home.page.ts:

import { Component } from '@angular/core';
 
@Component({
 selector: 'app-home',
 templateUrl: 'home.page.html',
 styleUrls: ['home.page.scss'],
})
export class HomePage {
 
 num:number;
 mayorMenor = '...';
 
  constructor() {}
 
}

 

C贸mo podemos observar para definir una variable ponemos el nombre de la variable y seguido de dos puntos 鈥:鈥 el tipo de valor que va a contener. Si lo deseamos podemos inicializar la variable con un valor en el momento de declararla.聽

En este caso num es de tipo number y mayorMenor de tipo string聽 aunque no es necesario ponerlo ya que al inicializarla con una cadena de texto autom谩ticamente se le asigna el tipo string.

La variable mayorMenor va a contener un texto con la palabra 鈥淢ayor鈥, 鈥淢enor鈥 o 鈥淚gual鈥 seg煤n sea el caso. Inicializamos la variable mayorMenor con tres puntos suspensivos 鈥溾︹.

Los tipos primitivos聽 de variable que podemos definir son:

  • number (Num茅rico).
  • string (cadenas de texto).
  • boolean (Booleano: true o false).
  • any (cualquier tipo).
  • Array.

Tambi茅n vamos a necesitar otra variable que contenga el n煤mero secreto que debemos adivinar, le vamos a llamar numSecret y c贸mo valor le vamos a asignar la respuesta a la llamada a una funci贸n llamada numAleatorio que crearemos a continuaci贸n.

Vamos a definir la variable numSecret de tipo number debajo de las dos variables anteriores:

numSecret: number = this.numAleatorio(0,100);

 

Hacemos referencia a la聽 funci贸n numAleatorio con this porque va a ser un m茅todo de la propia clase.

Ahora vamos a聽 crear la funci贸n numAleatorio que como su nombre indica nos devolver谩 un n煤mero aleatorio entre dos n煤meros:

numAleatorio(a,b)
{
    return Math.round(Math.random() * (b - a) + parseInt(a, 10));
}

 

Esta funci贸n recibe como par谩metros dos valores que ser谩n el rango m铆nimo y el m谩ximo para el n煤mero aleatorio, es este caso le estamos pasando 0 y 100 por lo que obtendremos un n煤mero aleatorio entre 0 y 100.

Por 煤ltimo vamos a crear la funci贸n compruebaNumero que se llama al pulsar el bot贸n Adivina que en la parte html como recordar谩s lo hemos definido as铆:

<ion-button expand="block" (click)="compruebaNumero()">Adivina</ion-button>

 

Y ahora en home.page.ts definimos la funci贸n dentro de la clase HomePage:

compruebaNumero(){
    if(this.num)
    {
      if(this.numSecret < this.num)
      {
        this.mayorMenor = 'menor que';
      }
      else if(this.numSecret > this.num)
      {
        this.mayorMenor = 'mayor que';
      }
      else{
        this.mayorMenor = '';
      }
    }
  }

 

Esta funci贸n compara el n煤mero secreto que est谩 contenido en la variable numSecret con el n煤mero introducido por el usuario que se aloja en la variable num y le asigna a la variable mayorMenor el texto 鈥渕enor que鈥, 鈥渕ayor que鈥 o 鈥渋gual a鈥 en funci贸n de si es menor, mayor o igual que esta.

Observa que debemos utilizar this para las variables ya que son atributos de la propia clase.

El c贸digo completo de home.page.ts quedar谩 de esta manera:

import { Component } from '@angular/core';
 
@Component({
  selector: 'app-home',
  templateUrl: 'home.page.html',
  styleUrls: ['home.page.scss'],
})
export class HomePage {
 
  num: number;
  mayorMenor = '...';
  numSecret: number = this.numAleatorio(0,100);
 
  constructor() {}
 
  numAleatorio(a, b) {
    return Math.round(Math.random() * (b - a) + parseInt(a, 10));
  }
 
  compruebaNumero(){
    if(this.num)
    {
      if(this.numSecret < this.num)
      {
        this.mayorMenor = 'menor que';
      }
      else if(this.numSecret > this.num)
      {
        this.mayorMenor = 'mayor que';
      }
      else{
        this.mayorMenor = '';
      }
    }
  }
}

 

Ahora si lo ejecutamos en el navegador con ionic serve -l (si no lo ten铆as ya en marcha), podemos ver un campo para introducir un n煤mero, y debajo un texto que dice 鈥渆l n煤mero secreto es 鈥 鈥, en estos momentos聽 no hay introducido ning煤n n煤mero por lo que aparecen los puntos suspensivos.

Si introducimos un n煤mero vemos que autom谩ticamente en el texto aparece ese n煤mero el mismo tiempo que lo escribimos. Eso es porque estamos realizando un Data Binding con la variable num. Al utilizar [(ngModel)]=鈥漬um鈥 en el campo input le estamos indicando que la variable coja el valor que introducimos en el input y lo refresque autom谩ticamente en todos los sitios donde se utilice, por ejemplo en el texto de debajo.Lo mismo ocurre si cambiamos el valor de la variable desde el c贸digo.

Por 煤ltimos si pulsamos el bot贸n adivina obtendremos algo como esto:

Al pulsar el bot贸n se ha ejecutado la funci贸n compruebaNumero(), dentro de la funci贸n se ha comprobado que el n煤mero secreto es mayor a 12 por lo que a la variable mayorMenor se le asigna el texto 鈥渕ayor que鈥.

Cuando acertemos el n煤mero secreto el texto dir谩 que el n煤mero secreto es el n煤mero introducido. Esto es un poco soso, vamos a hacer algunos cambios para que cuando acertemos el n煤mero nos muestre un mensaje felicit谩ndonos por haber acertado.

Este mensaje lo ponemos en la plantilla html pero solo se debe mostrar cuando se cumpla una condici贸n y es que la variable mayorMenor no contenga ning煤n texto, eso ocurre cuando hemos acertado ya que si el n煤mero introducido no es ni mayor ni menor, es decir que es es igual al n煤mero secreto hacemos la siguiente asignaci贸n this.mayorMenor = ”.

Vamos a a帽adir lo siguiente en home.page.html justo antes del bot贸n 鈥淎divina鈥:

<ion-card *ngIf="mayorMenor==''">
  <ion-card-header>
  隆隆隆Enhorabuena!!!
</ion-card-header>
<ion-card-content>
    Has acertado, el n煤mero secreto es el {{ num }}
</ion-card-content>
</ion-card>

 

Aprovecho la ocasi贸n para introducir otro componente de ionic: ion-card, las cards o 鈥渢arjetas鈥 son componentes que muestran la informaci贸n en un recuadro. Como vemos dentro contiene otros dos componentes <ion-card-header> y <ion-card-content>, Como habr谩s adivinado el primero permite mostrar una cabecera dentro de la tarjeta y el segundo el contenido que deseemos.

En la documentaci贸n oficial de ionic pod茅is ver todas las posibilidades que tiene ion-card: https://ionicframework.com/docs/v2/components/#cards

Queremos que est谩 card se muestre solo cuando la variable de nuestro controlador mayorMenor contenga una cadena vac铆a despu茅s de hacer la comprobaci贸n.

Aqu铆 entra en juego la directiva condicional *ngIf:

<ion-card *ngIf=“mayorMenor==””>

La directiva *ngIf es una directiva estructural, lo que significa que nos permite alterar el DOM (Document Object Model), estas directivas llevan un asterisco 鈥*鈥 delante.

Con *ngIf le estamos indicando que el elemento donde se encuentra, ion-card en este caso, solo se muestre si se cumple la condici贸n que tiene definida entre las dobles comillas. En este caso le estamos diciendo que solo se muestre el elemento ion-card cuando mayorMenor==鈥欌.

Sabiendo esto vamos a darle otra vuelta de tuerca m谩s y vamos a a帽adir un bot贸n para volver a jugar una vez que hemos acertado, este bot贸n llamar谩 a una funci贸n para volver a generar un nuevo n煤mero aleatorio y reiniciar谩 las variables para que se oculte el ion-card. Este bot贸n debe permanecer oculto hasta que hayamos acertado, y cuando se muestra debe ocultarse el bot贸n Adivina para que no podamos pulsarlo despu茅s de haber adivinado el n煤mero hasta que empecemos una nueva partida.

Editamos home.page.html y a帽adimos *ngIf al bot贸n Adivina para que solo se聽 muestre cuando no hemos acertado el n煤mero:

<ion-button *ngIf="mayorMenor!=''" expand="block" (click)="compruebaNumero()">Adivina</ion-button>

 

Ahora a帽adimos el bot贸n 鈥淰olver a Jugar鈥 justo despu茅s del de Adivina en home.page.html:

<ion-button *ngIf="mayorMenor==''" expand="block" (click)="reinicia()">Volver a Jugar</ion-button>

 

Con *ngIf indicamos que solo se muestre cuando hayamos acertado el n煤mero, es decir cuando la variable mayorMenor est茅 vac铆a, y en el evento (click) le indicamos que ejecute la funci贸n reinicia().

Por lo tanto ahora聽 vamos a editar nuestro controlador (home.page.ts) y a帽adimos la funci贸n reinicia(), que como hemos dicho debe reiniciar las variables para poder comenzar el juego:

 reinicia(){
   // reiniciamos las variables
   this.num = null;
   this.mayorMenor = '...';
   this.numSecret = this.numAleatorio(0,100);
 }

 

Si acertamos el n煤mero veremos algo como esto:

Vista de nuestro juego al acertar.
Vista de nuestro juego al acertar.

Ahora ya podemos volver a jugar una vez de que hemos adivinado el n煤mero.

Este juego se podr铆a mejorar a帽adiendo un contador de intentos. Podr铆amos limitar el n煤mero de intentos y mostrar un mensaje si se han consumido todos los intentos sin acertar el n煤mero secreto. Esto lo dejo como deberes para el que quiera practicar m谩s, sin duda experimentar y tratar de modificar el juego es una de las mejores formas de aprender.

Puedes descargar o clonar este proyecto desde GitHub en el siguiente link:

https://github.com/edurevilla/libro-ionic-adivina.git.

聽 Eso es todo por hoy,聽 nos vemos en el pr贸ximo post :).

Tutorial de IONIC: Estructura de un proyecto en IONIC

Estructura

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

Vamos a ver la estructura de carpetas y archivos que se generan al crear un proyecto ionic.

Al crear un proyecto con ionic se crea una carpeta con el nombre del proyecto y dentro de ella una estructura de archivos y directorios que contiene todos los elementos del proyecto. Vamos a echar un vistazo a la estructura de archivos y carpetas que se ha generado al crear nuestro proyecto hola-mundo:

Veamos qu茅 contiene cada carpeta:

e2e: Aqu铆 se encuentra el c贸digo para escribir tests end to end que prueben la aplicaci贸n, no nos vamos a preocupar de esta carpeta.


node_modules: La carpeta node_modules se genera autom谩ticamente al instalar las dependencias npm con 鈥渘pm install鈥. Este comando explora el archivo package.json para todos los paquetes que necesitan ser instalados. No necesitamos tocar nada en esta carpeta.

src: Esta es la carpeta m谩s importante y donde realizaremos la mayor parte de nuestro trabajo. Aqu铆 es donde est谩n los archivos con el contenido de nuestra aplicaci贸n, donde definimos las pantallas, el estilo y el comportamiento que tendr谩 nuestra aplicaci贸n.
Dentro de src tenemos las siguientes subcarpetas:聽

La carpeta app, que es donde se ubicar谩 las p谩ginas que creemos para la aplicaci贸n, los servicios y toda la l贸gica de programaci贸n.

La carpeta assets donde almacenaremos aquellos recursos que necesitemos para nuestra aplicaci贸n, como im谩genes etc.

La carpeta environments contiene un archivo llamado environment.prod.ts y un archivo llamado environment.ts. Ambos archivos exportan un objeto llamado environment donde podemos definir variables de entorno, por defecto contienen la variable variable production que podemos utilizar para diferenciar cuando vamos a ejecutar la aplicaci贸n en producci贸n en en modo desarrollo. De momento no nos vamos a preocupar por esto.

La carpeta theme contiene el archivo variables.scss donde se definen las variables css de ionic. Por defecto vienen definidos algunos colores que podemos utilizar.

El archivo global.scss: En este archivo podemos colocar css que se utilice globalmente en cualquier sitio de nuestra aplicaci贸n.

index.html: Es el punto de entrada de nuestra aplicaci贸n, la mayor铆a de las veces no necesitaremos cambiar nada aqu铆.

karma.conf.js: Es el archivo de configuraci贸n de karma, se utiliza para la realizaci贸n de test unitarios.

main.ts: Es el punto de entrada del m贸dulo principal de nuestra aplicaci贸n. No necesitaremos cambiar nada aqu铆.

polyfills.ts: Es un archivo de configuraci贸n que se genera al crear un proyecto angular, no necesitaremos modificar nada en el.

test.ts: Este archivo es requerido por karma.conf.js que como hemos comentado se utiliza para realizar tests unitarios.聽

tsconfig.app.json, tsconfig.spec.json y typings.d.ts:Contienen configuraciones typescript para los tests.

.editorconfig y .gitignore son dos archivos ocultos, as铆 que dependiendo de tu sistema puede que no los veas, est谩n relacionados con la configuraci贸n del editor de c贸digo y Git, en principio no tenemos que preocuparnos por ellos.

angular.json: Archivo de configuraci贸n de la app.

 

Ionic.config.json:聽 Contiene informaci贸n b谩sica sobre la configuraci贸n nuestro proyecto.

package.json: Contiene paquetes y dependencias de nodeJS.

tsconfig.json y tslint.json: Son archivos que contienen informaci贸n necesaria a la hora de compilar TypeScript, no necesitamos editar estos archivos.

Aunque pueda parecer complicado en realidad la mayor铆a de los elementos los gestiona autom谩ticamente Ionic y nosotros solo tenemos que preocuparnos de la carpeta src que es donde se va a situar nuestro c贸digo.

Modificando nuestro hola mundo

Ahora que ya hemos visto la estructura de un proyecto en ionic vamos a modificar nuestro hola-mundo para que realmente diga 鈥渉ola mundo鈥.

Si desplegamos el directorio src podemos ver la carpeta app, en esta carpeta es donde se van a alojar todas la p谩ginas que contenga nuestra aplicaci贸n. Para que nos entendamos una p谩gina ser谩 como una vista o un pantalla de nuestra aplicaci贸n.

Al crear un proyecto con la plantilla blank ionic genera por defecto una p谩gina llamada home, que como su propio nombre indica es la p谩gina inicial que se va a mostrar al iniciar nuestra aplicaci贸n. Esta p谩gina la podemos mantener como p谩gina principal y modificarla, o podemos eliminarla y crear otra con el nombre que nosotros queramos. De momento vamos a mantener la que nos ha creado por defecto y vamos a modificar su contenido.

Como podemos ver dentro de la carpeta de la p谩gina home que nos ha creado hay cinco archivos:

El archivo home.module.ts: En este archivo se importan los m贸dulos y funcionalidades requeridas.

El archivo home.page.html que contiene la plantilla html de la p谩gina.

El archivo home.page.scss que contiene el archivo sass donde podremos modificar el estilo de los componentes de la p谩gina.

home.page.spec.ts este archivo se utiliza para las pruebas unitarias, no nos vamos a preocupar de 茅l por ahora.

El archivo home.page.ts que es el archivos typescript que contiene el controlador de la p谩gina, donde definiremos el comportamiento de la misma, como por ejemplo la funci贸n con la l贸gica a ejecutarse cuando se pulse sobre un bot贸n de la p谩gina etc. Veremos m谩s adelante en profundidad cada una de las partes de una p谩gina.

Si abrimos el archivo home.page.html veremos que contiene algo como esto:

<ion-header [translucent]="true">
  <ion-toolbar>
    <ion-title>
      Blank
    </ion-title>
  </ion-toolbar>
</ion-header>
 
<ion-content [fullscreen]="true">
  <ion-header collapse="condense">
    <ion-toolbar>
      <ion-title size="large">Blank</ion-title>
    </ion-toolbar>
  </ion-header>
 
  <div id="container">
    <strong>Ready to create an app?</strong>
    <p>Start with Ionic <a target="_blank" rel="noopener noreferrer" href="https://ionicframework.com/docs/components">UI Components</a></p>
  </div>
</ion-content>


Las p谩ginas se pueden crear utilizando html puro, sin embargo aqu铆 podemos ver algunas etiquetas que no corresponden con las etiquetas html 鈥渆st谩ndar鈥. Lo que vemos aqu铆 son componentes de ionic.

Ionic nos ofrece una amplia gama de componentes listos para utilizar y que nos facilitar谩n la labor de crear nuestra interfaz de usuario con un estilo atractivo y profesional.

Iremos viendo聽 diferentes componentes de ionic seg煤n los vayamos necesitando a lo largo de este libro. En este enlace pod茅is consultar en la documentaci贸n oficial de ionic los componentes disponibles con peque帽os ejemplos de como implementarlos: https://ionicframework.com/docs/components/

Todos los componentes de ionic comienzan con el prefijo 鈥渋on-鈥.

C贸mo ionic est谩 basado en Web components si en alg煤n caso no nos es suficiente con los componentes que nos ofrece ionic podr铆amos crear nuestros propios componentes personalizados, aunque en la mayor铆a de los casos no ser谩 necesario ya que ionic nos ofrece una amplia gama de componentes para poder desarrollar nuestras aplicaciones.

Veremos m谩s sobre componentes en posteriores cap铆tulos.

En la p谩gina principal (y 煤nica de momento) de nuestro proyecto hola-mundo vemos que tenemos los siguientes componentes:

  • ion-header: Cabecera.
  • ion-navbar: Barra de navegaci贸n.
  • ion-title: T铆tulo.
  • ion-content: Contenido de la p谩gina.

Como puedes ver ion-header aparece dos veces, una dentro de la etiqueta ion-content con el par谩metro collapse=”condense”, esto es una nueva funcionalidad que trae ionic 5 y que solo es visible en IOS, al hacer scroll la cabecera se colapsa.
En los ejemplos de este libro no vamos a utilizar esta funcionalidad, pero si necesitas saber m谩s sobre c贸mo funcionan las cabeceras desplegables para iOS en ionic puedes consultar la documentaci贸n oficial de ionic al respecto en el siguiente link:

https://ionicframework.com/docs/api/title#collapsible-large-titles

Bien, vamos a cambiar el contenido de ion-title por 鈥淗ola Mundo鈥, tambi茅n vamos a borrar todo lo que hay dentro de la etiqueta ion-content y vamos a poner orgullosos 鈥<h1>隆隆隆隆Hola mundo!!!!<h1>鈥, as铆 el c贸digo de home.html deber铆a quedar de la siguiente manera:

<ion-header [translucent]="true">
  <ion-toolbar>
    <ion-title>
     Hola Mundo
    </ion-title>
  </ion-toolbar>
</ion-header>
 
<ion-content [fullscreen]="true">
  <div class="ion-padding">
    <h1>隆隆隆隆Hola mundo!!!!</h1>
  </div>
</ion-content>

Si desde el terminal,escribimos ionic serve -l 聽para ver desde el navegador como queda en las tres plataformas nuestra aplicaci贸n veremos algo como esto:

 

Eso es todo por hoy,聽 en el pr贸ximo post crearemos un mini juego para seguir aprendiendo a crear aplicaciones con este potente framework llamado IONIC.

Tutorial de IONIC: Introducci贸n

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

Hola todos:

Hace tiempo escrib铆 en este blog una serie de tutoriales sobre ionic, estos tutoriales estaban basados en ionic 2/3 y se han quedado desactualizados聽 con las 煤ltimas versiones de IONIC, aprovechando que acabo de sacar mi libro actualizado: Desarrollo de aplicaciones m贸viles multiplataforma y PWAs con Ionic y Firebase desde cero. voy a iniciar una serie de tutoriales sobre IONIC.

He decidido dejar los tutoriales antiguos avisando de que son para versiones antiguas de ionic, por si alguien necesita esa informaci贸n para mantener alguna aplicaci贸n antigua, y porque me es m谩s sencillo volver a escribir desde cero que adaptar los tutoriales que ya existen.

Sin m谩s pre谩mbulos vamos a empezar con una peque帽a introducci贸n:

驴Que es 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).

Para poder utilizar elementos web en una aplicaci贸n m贸vil utiliza lo que se conoce como una聽 Webview.

A este tipo de aplicaciones se las conoce como aplicaciones h铆bridas. El resultado final es una app 鈥渘ativa鈥 que puedes subir a las tiendas de apps.

Ionic nos ofrece un mont贸n de componentes para crear la interfaz de usuario con estilo nativo listos para utilizar por lo que podemos crear aplicaciones con una est茅tica profesional y con muy poco esfuerzo.

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 Web e incluso aplicaciones de escritorio utilizando Electron, 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.

Novedades a partir de la versi贸n 4 de IONIC

Ionic 2/3 estaba basado en Apache Cordova y Angular.

Apache cordova nos permite ejecutar nuestro c贸digo escrito con tecnolog铆a web (html, css, javascript) encapsulado en una webview y hace de puente entre esta y nos permite hacer uso de las funciones nativas del m贸vil (c谩mara, gps, etc) a trav茅s de plugins.

Sin embargo a partir de la versi贸n 4 de Ionic se incorpora Capacitor.

Capacitor

Al igual que lo hac铆a apache cordova, Capacitor hace de puente entre nuestra aplicaci贸n web y el dispositivo nativo.

Capacitor adem谩s se integra mejor cuando ejecutamos nuestra aplicaci贸n en otros entornos que no sean dispositivos m贸viles como en navegadores de escritorio facilitando el desarrollo de progressive web apps (PWA).

Hasta la versi贸n 4 Ionic utilizaba Angular como framework de desarrollo para crear componentes web basados en angular.聽

A partir de la versi贸n 4 Ionic utiliza componentes web gen茅ricos, para crear los Web Components, el equipo de Ionic cre贸 una herramienta llamada Stencil.

Los Web components son un conjunto de web APIs que te permiten crear etiquetas HTML personalizadas que son reutilizables.

Stencil

Stencil es una herramienta que crea componentes web, y el equipo Ionic ha creado un conjunto de componentes web con Stencil que forman parte de Ionic Core.聽

Ionic Core contiene el conjunto de los componentes web que componen la biblioteca de la interfaz de usuario de Ionic (listas, botones, selectores, etc.).

Nosotros no necesitamos utilizar Stencil ni entender c贸mo funciona para utilizar los componentes que el equipo de ionic a creado para nosotros.聽

Angular

Al utilizar componentes web gen茅ricos y no componentes Angular podemos utilizar cualquier framework por lo que no es obligatorio el uso de Angular. Si te sientes m谩s c贸modo utilizando otro framework puedes hacerlo.

Sin embargo en este tutorial vamos a utilizar Angular para desarrollar nuestras aplicaciones ya que Angular nos proporciona muchas cosas listas para usar que nos ayudan a construir aplicaciones bien estructuradas.聽

Hay una biblioteca llamada @ionic/angular que es la biblioteca de ionic espec铆fica de Angular, es la que ya ven铆amos utilizando antes de la versi贸n 4 de ionic, este paquete ofrece funcionalidades adicionales que solo se pueden utilizar con Angular, sin embargo utiliza los mismos componentes web que pueden ser utilizados con otro framework.聽

Angular nos permite aprovechar las ventajas de este framework, adem谩s como Angular siempre ha sido el framework por defecto de Ionic hay mucho m谩s soporte y muchas m谩s apps desarrolladas con ionic utilizando Angular.

Adem谩s hay muchas librer铆as y utilidades ya creadas en Angular para utilizar con Ionic.

Angular utiliza TypeScript como lenguaje de programaci贸n, si no dominas estas tecnolog铆as mencionadas no te preocupes, tratar茅 de ir explicando las cosas b谩sicas necesarias seg煤n las vayamos necesitando en los ejemplos que realizaremos.

La versi贸n 4 de Ionic tambi茅n trae cambios en la navegaci贸n entre p谩ginas utilizando ahora el router de Angular.

Tambi茅n cambian en la versi贸n 4 los ciclos de vida de las p谩ginas, ya no utilizamos por ejemplo ionWillLoad o ionViewDidEnter, en su lugar utilizaremos ngOnInit.

Si vienes de utilizar ionic en versiones anteriores te ser谩 煤til conocer estas diferencias, si empiezas de cero no te preocupes, veremos todo lo que necesitas saber para desarrollar aplicaciones con Ionic en la versi贸n actual.

Vamos a ver como instalar Ionic y todas la herramientas necesarias para empezar a desarrollar tus aplicaciones con Ionic.

Instalar Node.js

Para instalar ionic debemos instalar primero Node.js para ello descargamos el paquete con la versi贸n LTS de http://nodejs.org/ y lo instalamos.聽

Si est谩s usando linux y quieres utilizar un gestor de paquete puedes consultar aqu铆 los pasos a seguir para instalar Node.js usando un gestor de paquetes seg煤n la distribuci贸n que tengas instalada:

https://nodejs.org/es/download/package-manager/

Instalar ionic

Una vez instalado nodejs abrimos un terminal (consola del sistema) e instalamos ionic con el siguiente comando:

npm install -g ionic

 

Una vez instalado ya podemos crear aplicaciones con ionic y ejecutarlas en el navegador, sin embargo para poder ejecutarlas en un dispositivo o emulador Android debemos instalar las herramientas de desarrollo de Android, as铆 mismo para poder ejecutar la app para IOS necesitaremos instalar Xcode.

Cabe mencionar que aunque Android Studio lo podemos instalar en cualquier plataforma, es decir podemos desarrollar para Android desde un pc con Windows, Linux o MAC, para poder compilar las Apps para IOS necesitamos un MAC con Xcode instalado.

Para instalar Android Studio descargalo desde la p谩gina oficial y sigue las instruci贸nes dependiendo de tu sistema operatico: https://developer.android.com/studio/index.html.

Para instalar Xcode en Mac solo tenemos que buscarlo en la App Store e instalarlo, es gratuito.

Por 煤ltimo necesitaremos un editor de c贸digo que nos coloree typescript para facilitarnos el trabajo. En realidad podr铆amos editar el c贸digo con cualquier editor de texto plano, pero una buena opci贸n para typescript es utilizar Visual Studio Code de Microsoft que es multiplataforma y pod茅is descargarlo desde el siguiente enlace:聽 https://code.visualstudio.com/

Hola Mundo en Ionic

Vamos a crear nuestra primera aplicaci贸n con Ionic, el famoso 鈥渉ola mundo鈥 que siempre es el punto inicial en el aprendizaje de cualquier lenguaje de programaci贸n o framework.

Para crear nuestro proyecto 鈥渉ola mundo鈥 iremos a la consola de comandos o terminal y escribimos el siguiente comando:

ionic start hola-mundo blank

 

Seleccionamos Angular como framework y tras un rato descargando los paquetes necesarios para crear nuestra aplicaci贸n ya estar谩 listo nuestro proyecto.

El comando start de ionic cli (commandline interface)聽 se utiliza聽 para crear (iniciar) un nuevo proyecto, el siguiente par谩metro es el nombre del proyecto, en este caso hola-mundo, el siguiente par谩metro es el tipo de plantilla que vamos a utilizar, en este caso blank que indica que utilizaremos una plantilla vac铆a.

Existen tres tipos de plantillas:

  • blank : Crea una plantilla vac铆a.
  • sidemenu: Crea una plantilla con men煤 lateral.
  • tabs: Crea una plantilla con Tabs (Pesta帽as).聽

Para ver el resultado en el navegador debemos entrar dentro de la carpeta del proyecto 鈥榟ola-mundo鈥 que se acabamos de crear con ionic start y escribimos el siguiente comando:

ionic serve -l

 

Podemos utilizar simplemente ionic serve, pero con el par谩metro -l nos muestra como queda nuestra app en IOS, Android聽 y Windows.

Para poder ejecutar ionic serve con el par谩metro -l tenemos que instalar @ionic/lab, por eso la primera vez que lo ejecutemos nos pedir谩 que instalemos el paquete @ionic/lab:

Install @ionic/lab? (Y/n)

Le decimos que s铆 pulsando la tecla 鈥Y鈥.

En la barra superior a la derecha desplegando la opci贸n platforms podemos seleccionar en qu茅 plataformas queremos ver c贸mo queda nuestra aplicaci贸n.Vista de c贸mo quedar铆a nuestra primera App con plantilla Blank en el navegador.

Si no utilizamos -l mostrar谩 solo una plataforma a pantalla completa.

Como podemos ver,聽 sin nosotros hacer nada tenemos creada la estructura de una app que podremos modificar para a帽adir lo que necesitemos.

Eso es todo por hoy,聽 el el pr贸ximo post analizaremos la estructura de un proyecto de IONIC y veremos c贸mo empezar a modificar nuestro Hola Mundo.

Libro: Desarrollo de aplicaciones m贸viles multiplataforma y PWAs con Ionic y Firebase desde cero.

Hola a todos,

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 鈥淚temSliding鈥
    • 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:

Lo puedes encontrar en versi贸n tapa blanda:

https://www.amazon.es/dp/1700622722

Tambi茅n est谩 disponible en Kindle:

 

No quiero aburriros m谩s as铆 que muchas gracias a todos los que me hab茅is apoyado 馃檪

Un saludo y hasta el pr贸ximo post.

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