Archivo de la etiqueta: apps hibridas

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 “Hola 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 “Adivina 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 “mayor que” en caso de que el número secreto sea mayor al introducido, “menor que” en caso de ser menor e “igual 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:’app-home’, que es el selector que se va a aplicar a la página,  templateUrl:’home.page.html’ que es la plantilla html que va a renderizar la página y styleUrls: [‘home.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)]=”num” 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 “Mayor”, “Menor” o “Igual” 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 “menor que”, “mayor que” o “igual 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 “el 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)]=”num” 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 “mayor 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 “Adivina”:

<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 “tarjetas” 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 “Volver 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 :).