viernes, 21 de septiembre de 2018

Angular: 16. Peticiones HTTP

Vamos a ver cómo obtener información de otro sitio web a través de una petición HTTP.

Vamos a entrar en la página "restcountries.eu", que posee un servicio de datos disponible para acceder a ellos mediante http. Vamos a buscar una lista de países cuyo idioma sea el español.
Para ello, entramos en la página, pulsamos en el menú "Language" y nos guardamos la url señalada en la imagen:


Ahora vamos a modificar el "app.module.ts" para importar el componente "HttpClientModule":



Vamos a elegir el componente "home" para capturar y mostrar los datos. Abrimos el "home.component.ts" y lo modificamos como sigue:


Como se puede ver, lo primero que hacemos es importar el "HttpClient".
Después nos creamos una variable de arrays llamada "paises".
En el constructor de la clase es donde hemos realizado la mayor modificación.
En primer lugar inyectamos en el constructor una variable "http" de la clase "HttpClient".
En segundo lugar realizamos la petición http en sí misma, haciendo un "get" de la dirección que copiamos antes de la web de países y añadiendo en el "subscribe" una función de flecha que vamos a utilizar para guardar la respuesta de la petición (la lista de países) en nuestra variable de clase "paises". Por último aprovechamos la función para mostrar a través de la consola el contenido de la respuesta.

Ahora simplemente modificamos el "home.component.html" para que muestre la lista de países mediante la directiva "*ngFor":


Y comprobamos que realmente se muestra la lista de países, y el contenido de la respuesta de la petición en la consola:


Y eso es todo.

martes, 18 de septiembre de 2018

Angular: 15. Pipes personalizados. Domseguro

Ahora vamos a crear un pipe que normalmente se utilizará para cualquier aplicación que cargue datos de otra página web, como Youtube, Spotyfy, o similares.

Primero vamos a crearnos un nuevo pipe mediante el comando "ng g p pipes/domseguro", que nos creará los ficheros necesarios.

Vamos a explicar el problema por el que necesitamos crear este pipe.
Imaginemos que queremos insertar en nuestra página un vídeo de Youtube. Para eso basta con copiar el código que nos muestra Youtube en nuestra página html:


Si copiamos el código y levantamos la aplicación, comprobaremos que el vídeo funciona perfectamente.
Ahora imaginemos que queremos crear una aplicación que recopile varios vídeos de Youtube y que muestre el vídeo que sea oportuno en cada momento. Si este es el caso, lo normal sería que, en lugar de copiar todos los códigos de los vídeos de Youtube que queremos, mostremos sólo una ventana de vídeo en la pantalla y que carguemos en ella el vídeo necesario en cada momento, guardando la ruta "src" en una variable que cogería el valor del vídeo elegido:


Como se puede ver, todos los vídeos de Youtube tienen en común como fuente la cadena "https://www.youtube.com/embed/", seguida del identificador propio del vídeo, en este caso "8vxXVhUDEwo".
Lo normal es que utilicemos una variable para guardar el identificador del vídeo ("8vxXVhUDEwo" en este caso) que concatenaremos a la ruta base ("https://www.youtube.com/embed/") en el atributo "src" de la etiqueta.
Sin embargo, si hacemos esto nos saltará un error diciendo que la ruta no es segura y no podremos ver el vídeo. Esto lo solucionaremos con nuestro nuevo pipe.

Modificaremos el pipe como sigue:


Como podemos ver, hemos importado el componente "DomSanitizer", que es el que nos permitirá marcar una ruta como segura para que no nos de error el navegador.
Después lo hemos inyectado en el constructor del pipe.
Por último, en la función del pipe en sí, devolvemos la concatenación del parámetro "url" con el valor "value" (que será "https://www.youtube.com/embed/" + "8vxXVhUDEwo") marcado como seguro.

El pipe es así de sencillo. Ahora sólo tenemos que crear en el TypeScript del componente de la página una variable que contenga el identificador del vídeo:


Y modificar el código html del vídeo como sigue a continuación para utilizar el pipe:


Y comprobamos que ahora el vídeo funciona correctamente:


Y eso es todo. A partir de ahí, simplemente podemos cambiar el valor de la variable del TypeScript para cargar cualquier vídeo en esa ventana.

domingo, 16 de septiembre de 2018

Angular: 14. Pipes personalizados. Capitalización

Ahora vamos a crearnos un Pipe personalizado por nosotros mismos.

Vamos a crearnos un Pipe que capitalice una cadena de texto, es decir, que la primera letra la pase a mayúscula y el resto la pase a minúsculas. Es más vamos a incluirle un parámetro booleano (verdadero o falso) para distinguir si queremos capitalizar sólo la primera letra de toda la frase, o si queremos capitalizar la primera letra de cada palabra de la frase.

Aunque los Pipes se pueden crear por consola con el Ancular CLI como el resto de componentes, vamos a crearlo esta vez de forma manual.

Primero nos creamos una carpeta "pipes" dentro de "app", y luego un fichero "capitalizado.pipe.ts" dentro de la misma:


El fichero "capitalizado.pipe.ts" lo informamos con lo siguiente:


Como podemos ver, no es más que una clase con la función "transform", que es la que se lanza al ejecutar el Pipe. Esta función tiene el parámetro "value", que es la variable sobre la que ejecutamos el Pipe, y otra booleana, que es la primera variable opcional que le podemos pasar al Pipe. Esta variable la inicializamos a verdadero en el constructor para que tenga el valor "true" por defecto, es decir, si no se la pasamos al ejecutar el Pipe.

La función lo único que hace es capitalizar la primera palabra o todas según el parámetro booleano.

Ahora tenemos que declarar el Pipe en el fichero "app.module.ts", como cualquier otro componente:


Con esto sería todo, ya sólo falta declarar una variable string en el TypeScript para utilizar nuestro Pipe:


Y utilizamos la variable y el Pipe en nuestro html. Hacemos la prueba con y sin parámetro booleano para probar los resultados:


Y aquí está el resultado:


Esto sería todo.

Como nota adicional, para crear un Pipe mediante comandos del Angular CLI, un ejemplo sería así:
"ng g p pipes/capitalizacion".

sábado, 15 de septiembre de 2018

Angular: 13. Pipes

Vamos a ver qué son los pipes o "formateadores" de Angular.

Los Pipes son una forma de dar formato específico a los datos que mostramos en pantalla. Por ejemplo, podemos tener una variable llamada "Fernando", y queremos que, al mostrarla por la pantalla, aparezca como "FERNANDO", con todas las letras en mayúscula, PERO SIN AFECTAR AL VALOR DE LA VARIABLE, es decir, que el cambio sea sólo visual y que la variable dentro del programa siga teniendo el valor "Fernando". Para eso sirven los Pipes.
El uso más común de los Pipes es dar formato a las fechas (objetos de tipo Date) y que se muestren de una forma u otra según nuestras necesidades.

Vamos a ver el código de un programa sencillo en el que incluimos muchos de los pipes predefinidos por Angular y su resultado.

Se trata simplemente de una tabla de 3 columnas en la que mostramos el valor de una variable, el Pipe que le aplicamos, y el resultado de éste sobre la variable. Sólo tenemos que modificar el código html (para mostrar los datos) y el TypeScript (para crear las variables que utilizará el html) del componente inicial de la aplicación como sigue:

app.component.ts

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

@Component({
  selector: 'app-root',
  templateUrl: './app.component.html',
  styleUrls: ['./app.component.css']
})
export class AppComponent {

  nombre:string = "Fernando";
  arreglo:number[] = [1,2,3,4,5,6,7,8,9,10];
  PI:number = Math.PI;
  a:number = 0.234;
  salario:number = 1234.5;
  heroe = {
    nombre: "Logan",
    clave: "Worverine",
    edad: 500,
    direccion: {
      calle: "Primera",
      casa: "19"
    }
  }
  valorDePromesa = new Promise( (resolve, reject) => {
    setTimeout( () => resolve('LLego la data!'), 3500 );
  } );
  fecha:Date = new Date();

}

app.component.html

<div class="container">

  <br>
  <h1>Pipes</h1>
  <hr>

  <table class="table">
    <thead class="thead-dark">
      <tr>
        <th scope="col">Variable</th>
        <th scope="col">Pipe</th>
        <th scope="col">Producto</th>
      </tr>
    </thead>
    <tbody>
      <tr>
        <td> {{ nombre }} </td>
        <td> uppercase </td>
        <td> {{ nombre | uppercase }} </td>
      </tr>
      <tr>
        <td> {{ nombre }} </td>
        <td> lowercase </td>
        <td> {{ nombre | lowercase }} </td>
      </tr>
      <tr>
        <td> {{ nombre }} </td>
        <td> slice:3 </td>
        <td> {{ nombre | slice:3 }} </td>
      </tr>
      <tr>
        <td> {{ nombre }} </td>
        <td> slice:0:3 </td>
        <td> {{ nombre | slice:0:3 }} </td>
      </tr>
      <tr>
        <td> {{ arreglo }} </td>
        <td> slice:1:5 </td>
        <td> {{ arreglo | slice:1:5 }} </td>
      </tr>
      <tr>
        <td> {{ PI }} </td>
        <td> number </td>
        <td> {{ PI | number }} </td>
      </tr>
      <tr>
        <td> {{ PI }} </td>
        <td> number:'1.0-2' </td>
        <td> {{ PI | number:'1.0-2' }} </td>
      </tr>
      <tr>
        <td> {{ a }} </td>
        <td> percent </td>
        <td> {{ a | percent }} </td>
      </tr>
      <tr>
        <td> {{ a }} </td>
        <td> percent:'2.2-2' </td>
        <td> {{ a | percent:'2.2-2' }} </td>
      </tr>
      <tr>
        <td> {{ salario }} </td>
        <td> currency </td>
        <td> {{ salario | currency }} </td>
      </tr>
      <tr>
        <td> {{ salario }} </td>
        <td> currency:'EUR' </td>
        <td> {{ salario | currency:'EUR' }} </td>
      </tr>
      <tr>
        <td> {{ salario }} </td>
        <td> currency:'EUR':false </td>
        <td> {{ salario | currency:'EUR':false }} </td>
      </tr>
      <tr>
        <td> {{ salario }} </td>
        <td> currency:'EUR':true:'4.0-0' </td>
        <td> {{ salario | currency:'EUR':true:'4.0-0' }} </td>
      </tr>
      <tr>
        <td> {{ salario }} </td>
        <td> number:'.2-2' </td>
        <td> {{ salario | number:'.2-2' }} </td>
      </tr>
      <tr>
        <td> {{ valorDePromesa }} </td>
        <td> async </td>
        <td> {{ valorDePromesa | async }} </td>
      </tr>
      <tr>
        <td> {{ fecha }} </td>
        <td> date </td>
        <td> {{ fecha | date }} </td>
      </tr>
      <tr>
        <td> {{ fecha }} </td>
        <td> date:'medium' </td>
        <td> {{ fecha | date:'medium' }} </td>
      </tr>
      <tr>
        <td> {{ fecha }} </td>
        <td> date:'MMMM - dd' </td>
        <td> {{ fecha | date:'MMMM - dd' }} </td>
      </tr>
    </tbody>
  </table>

  <h4>Slice</h4>
  <ul>
    <li *ngFor="let item of arreglo | slice:5:20"> {{ item }} </li>
  </ul>

  <h4>JSON</h4>
  <pre> {{ heroe | json }} </pre>

</div>

Si levantamos la aplicación, obtenemos como resultado la siguiente tabla, en la que se ve claramente el efecto de cada Pipe sobre cada variable:




Y eso es todo. Hay más Pipes que se pueden obtener de la documentación oficial de Angular.

miércoles, 12 de septiembre de 2018

Angular: 12. @Output. Pasar un evento de un componente hijo a uno padre

Esta vez vamos a ver el caso contrario, pasar información de un componente hijo a su pcomponente padre.

Hay que hacer una distinción. En la entrada anterior, cuando pasamos información de un padre a su hijo, estábamos pasando parámetros, es decir, variables con cierta información.
Ahora que vamos a pasar información de un hijo a su padre, lo que vamos a pasar es un evento, dentro del cual incluiremos las variables que queramos, en lugar de pasar las variables directamente.

En nuestra aplicación, tras separar los componentes de lista de tarjetas (padre) de la tarjeta en sí (hijo), nos ha quedado una función "verHeroe" en el componente tarjeta que es la que muestra el detalle del héroe.
Lo que vamos a hacer es cambiar de lugar esa funcionalidad y que se encargue el padre de mostrar el detalle del héroe seleccionado. Es decir, vamos a hacer que, al hacer click en el detalle de una tarjeta, el identificador del héroe seleccionado viaje al componente padre (la lista de tarjetas) y que desde allí se llame a la función "verHeroe" que nos muestre el detalle.

Lo primero que vamos a hacer es copiar la función "verHeroe" del fichero "heroe-tarjeta.component.ts" (hijo) y pegarla en el fichero "heroes.component.ts". Después comentamos el contenido de la función "verHeroe" del fichero "heroe-tarjeta.component.ts".
Ahora para ver el detalle del héroe necesitamos llamar a la función del componente padre (lista de héroes) desde el componente hijo (héroe en sí).

Para hacerlo, modificamos la parte TypeScript del componente hijo como sigue:


Como se puede ver, primero hemos importado el Output y el EventEmitter del @Angular/core.
Después hemos creado una variable "heroeSeleccionado" que es de tipo "EventEmitter" y que va a emitir un dato de tipo numérico. Lleva el "@Output" delante para indicar que lo vamos a enviar.
A continuación inicializamos la variable en el constructor de la clase.
Por último, en la función "verHeroe", tras comentar la línea anterior, hacemos que se envíe el evento "heroeSeleccionado" y que se lleve consigo la variable "index" de tipo numérico que ya se encontraba en la clase antes (está señalada en la captura con una flecha) y que indica el héroe seleccionado.

Con esto hecho, cada vez que pulsemos el botón detalle de uno de los héroes, estamos enviando al componente padre la información de qué héroe ha sido pulsado. Ahora debemos hacer que el componente padre recoja correctamente la información y lance la función adecuada.

Para ello modificamos el componente html del padre ("heroes.component.html") como sigue:


Como se puede ver, dentro de la etiqueta del componente hijo hemos incluido un nuevo escuchador de eventos llamado "heroeSeleccionado" (mismo nombre que le dimos al evento en el componente hijo), que llamará a la función "verHeroe" DEL COMPONENTE PADRE, y que le pasará como parámetro una variable "$event", que se corresponde con la variable "index" del componente hijo.

Y con esto sería todo. La función "verHeroe" debería mostrar el detalle del héroe seleccionado tal y como lo teníamos anteriormente.

martes, 11 de septiembre de 2018

Angular: 11. @Input. Pasar información de un componente padre a uno hijo

Hemos visto cómo pasar parámetros entre rutas. Ahora vamos a ver cómo pasar parámetros de un componente padre a otro hijo.

Siguiendo con nuestra aplicación, teníamos el componente de héroes en el que mostrábamos una lista de héroes. Esta lista de héroes era un contenedor de tarjetas dentro de la cual metíamos una única tarjeta que copiábamos con la directiva *ngFor.

Lo que vamos a hacer ahora es separar el contenedor de tarjetas de las tarjetas en sí, poniendo cada una en un componente distinto. La directiva *ngFor la seguiremos utilizando, pero esta vez, en lugar de utilizarla en la tarjeta en sí para copiarla, la utilizaremos en el contenedor de tarjetas para que copie el componente de la tarjeta.
De esta forma podemos reutilizar el código de las tarjetas para alguna otra pantalla y no sólo para la lista de héroes.

Creamos el nuevo componente y pegamos en el html el mismo código de la tarjeta que teníamos en el componente:


En la parte TypeScript del componente es donde está la gracia, lo modificamos como sigue:


Como se puede ver, primero importamos el Input del @Angular/core, lo que nos permite recibir parámetros.
Después declaramos las variables "heroes" y "index" de forma normal, excepto que hemos puesto delante el código "@Input()". Con ése código estamos indicando que esas variables pueden venir con valor desde un componente padre. Si llegaran sin valor, se crearían de forma normal sin ningún problema.

Por último, modificamos el html del componente del contenedor de tarjetas, eliminando todo el código de las tarjetas (excepto el contenedor) y sustituyéndolo por la etiqueta del nuevo componente, pasando las variables e incluyendo la directiva *ngFor para que copie el componente por cada héroe que venga en el array:


Como se puede ver, añadimos la etiqueta del nuevo componente y le incluimos los parámetros "heroe" y "index", de la siguiente forma "[heroe]="heroe"".
La variable entre corchetes debe coincidir con la del TypeScript del componente de las tarjetas, es decir, la variable destino.
La variable entre comillas debe coincidir con la variable del *ngFor.
De esta forma le estamos diciendo a la aplicación que cargue un componente tarjeta por cada héroe en el array, y le pasamos sus datos.


Y eso es todo.

domingo, 9 de septiembre de 2018

Angular: 10. Rutas con parámetros

Ya hemos visto cómo utilizar las rutas para viajar de una parte de la aplicación a otra. Ahora vamos a ver lo mismo pero enviando y recibiendo parámetros entre las rutas.

Utilizando la aplicación anterior, vamos a crear un nuevo componente para que al elegir un héroe de la lista de héroes, nos muestre el detalle del héroe elegido en otra página. A priori parece básicamente una navegación básica como las que hicimos en el menú, y en realidad es así. Sin embargo, aquí la gracia consiste en que tenemos que enviar a la nueva página un identificador para que ésta sepa qué héroe hemos elegido y, por tanto, qué datos cargar.

Lo primero que tenemos que hacer es crearnos un nuevo componente llamado "heroe" (así en singular, ya que el componente "heroes" en plural es el que utilizamos para mostrar la lista de héroes) que será el que cargue los datos de cada personaje cuando los enviemos:


A continuación debemos importar e incluir la ruta a nuestro componente en el fichero "app.routes.ts":


Como se puede comprobar, al incluir la ruta en el fichero hemos puesto como camino "'heroe/:id'". Esto significa que cada vez que entremos en esa ruta (cada vez que pulsemos en el botón de ver detalle de algún héroe) vamos a enviar un parámetro llamado "id", que será el identificador del héroe pulsado, para que la aplicación sepa de qué héroe debe cargar los detalles.

Ahora debemos configurar el fichero html del componente de la lista de héroes para que el botón de detalle de cada héroe:
1. Nos envíe a la pantalla de detalles.
2. Le envíe a la pantalla de detalles el identificador del Héroe cuyo botón ha sido pulsado.

Para ello, como hemos dicho antes, vamos a modificar el fichero "heroes.component.html":


Como podemos ver, hemos añadido al *ngFor de las tarjetas de los personajes una variable "i" que tendrá el valor del index del bucle, es decir, que el primer héroe será el 0, el segundo el 1, el tercero el 2, etc.
Por otra parte, hemos añadido al botón la llamada a una nueva función "verHeroe" en el evento "onclick", a la que le pasamos la variable "i" que describimos antes.

Ahora queda modificar el componente para definir la función "verHeroe" del botón, que se encargará de llamar a la ruta del detalle del héroe y de pasar el identificador:


Como se puede ver, primero hemos importado el Router de Angular (que sirve para viajar a otra ruta), y luego lo hemos inyectado en la clase "HeroesComponent" mediante su constructor. Por último, hemos creado la función "verHeroe", en la que lo único que hacemos es llamar a la ruta "heroe", pasando como parámetro la variable identificador (a la que hemos llamado "idx" aquí).

Con esto ya estarían listos tanto la llamada a la página del detalle como el envío del parámetro identificador. Ahora debemos ver cómo podemos recibir ése parámetro desde la página de destino, en éste caso el componente "heroe" en singular.

Vamos a utilizar el servicio "heroes" que ya tenemos creado para mostrar los datos de detalle del héroe. Esto significa que el servicio "heroes" será utilizado tanto por el componente "heroes" (para mostrar la lista de héroes, como tenemos hasta ahora) como por el componente "heroe" (para mostrar el detalle del héroe elegido).

Vamos a modificar, por tanto, el servicio "heroes":


Como se puede ver, hemos creado una función "getHeroe" que es muy similar a la función "getHeroes" (que utilizamos para mostear la lista de héroes) que se encuentra en la parte superior, con la diferencia de que aquí le pasamos como parámetro un id, y que aquí no devolvemos la lista completa de héroes, sino que sólo devolvemos el héroe que se encuentre en la posición "idx" de la lista de héroes.

Tras esto, modificamos el componente "heroe" ("heroe.component.ts") para que reciba el parámetro enviado desde la lista de héroes y guarde el héroe indicado en una variable:


Como podemos ver, lo primero que hemos hecho es importar el ActivatedRoute de Angular (que nos permite recibir parámetros) y el HeroesService para poder utilizar sus funciones.
Después creamos una variable "heroe" en la clase de tipo objeto. Para hacerlo más correcto, la variable debería ser de tipo "Heroe" en lugar de tipo "any" y deberíamos importar la interfaz Heroes también, pero comprobaremos que así también funciona.
Por último, hemos modificado el constructor, que es donde está todo lo importante:
1. Inyectamos el ActivatedRoute y el HeroesService.
2. Llamamos a la función "subscribe" del ActivatedRoute, dentro de la cual llamamos a la función "getHeroe" del servicio pasando el parámetro recibido, y guardando el resultado en la variable "heroe" de la clase.

Con ésto ya tendríamos cargado el héroe indicado en nuestro componente. Sólo nos queda modificar el html del componente "heroe" para que muestre los datos por la pantalla:


Y probar que funciona correctamente:




Y eso es todo.

TypeScript: Ejercicios básicos

// Uso de Let y Const
let nombre:string = "Ricardo Tapia";
let edad:number = 23;
const PERSONAJE : { nombre:string, edad:number } = {
nombre: nombre,
edad: edad
};

jueves, 6 de septiembre de 2018

Angular: 9. Servicios de datos

Vamos a ver qué son los servicios en Angular y para qué sirven.

Como casi todo en Angular, los servicios son clases TypeScript. Su propósito es contener lógica de negocio, clases para acceso a datos o utilidades de infraestructura. Estas clases son perfectamente instanciables desde cualquier otro fichero que las importe. Pero Angular nos sugiere y facilita que usemos su sistema de inyección de dependencias.

Básicamente un servicio es un proveedor de datos, que mantiene lógica de acceso a ellos y operativa relacionada con el negocio y las cosas que se hacen con los datos dentro de una aplicación. Los servicios serán consumidos por los componentes, que delegarán en ellos la responsabilidad de acceder a la información y la realización de operaciones con los datos.

Vamos a crear un servicio sencillo. Primero creamos una carpeta "services" dentro de la carpeta de "app". Y dentro de la carpeta "services" creamos un fichero nuevo llamado "heroes.service.ts", que será nuestro servicio, y lo informamos con el siguiente código:


Como se puede ver, no es más que una clase con un código parecido al de un componente, solo que utilizamos el decorador "Injectable" en lugar del "Component". Dentro del constructor hemos puesto una frase para que escriba en el log cuando se ejecute el servicio.

Una vez terminado el servicio, debemos añadirlo al fichero "app.module.ts", al igual que como hacíamos con los componentes. Debemos importarlo y declararlo en la parte de "providers", tal y como se ve a continuación:



Por último, debemos insertar el servicio en un componente. Lo ideal es que cada componente tenga su propio servicio, de ahí que sea recomendable nombrar el servicio de la misma forma que el componente. En éste caso, vamos a configurar el componente "heroes.component,ts" para que utilice los datos del nuevo servicio "heroes.service.ts". Modificamos el fichero "heroes.component,ts" como se ve a continuación:


Como se puede ver, hemos importado el servicio en la línea 2 del fichero, y le hemos inyectado el servicio al componente en el constructor de éste último, en la línea 11, pasándole un objeto de la clase del servicio como parámetro de entrada. Con ésto, el componente ya puede utilizar el servicio sin problemas.

Aquí vamos a hacer un inciso sobre el tema de la inyección de dependencias en TypeScript.

Cuando TypeScript detecta el modificador de visibilidad "public" o "private" en el parámetro enviado al constructor, inmediatamente declara una propiedad en la clase y le asigna el valor recibido en el constructor. Por tanto, esta declaración:

export class HeroesComponent implements OnInit {
  constructor(private _heroesService:HeroesService) { }
}

Sería equivalente a escribir todo el código siguiente:

export class HeroesComponent implements OnInit {
  private _heroesService:HeroesService;
  constructor(_heroesService:HeroesService) {
    this._heroesService = _heroesService;
  }
}

En resumen, TypeScript entiende que, si defines la visibilidad de un parámetro en el constructor, lo que quieres hacer en realidad es crear una propiedad en el objeto recién construido, con el valor recibido por parámetro.

Bien. Tras esta explicación, ya podemos ver el resultado del código. Ejecutamos la aplicación, y al pulsar la sección de héroes del menú, vemos que se ejecuta el código que insertamos en el constructor del servicio:


Vamos ahora a modificar el servicio para utilizarlo como proveedor de datos para el componente. Vamos a crear un array de datos en el servicio, que posteriormente será utilizado por el componente para mostrarlo por la pantalla.

Primero vamos a modificar el servicio "heroes.service.ts" y, al final del fichero, fuera de la clase, vamos a crear una interface "Heroe" con los datos y tipos que aparecen a continuación:


Después, dentro de la clase "HeroesService", declaramos una propiedad array del tipo de la interfaz "Heroe" que acabamos de crear antes, y lo rellenamos con datos de ejemplo como aparece a continuación:


Por último, dentro de la clase, creamos una función "getHeroes" que nos devuelva la propiedad "heroes":


Ya hemos terminado de modificar el servicio. Ahora modificamos el componente "heroes.component.ts" como se ve a continuación:


Como se puede ver, primero hemos añadido la interfaz "Heroe" a la lista de importaciones en la línea 2.
Depués, en la línea 11, hemos creado una propiedad del tipo de la interfaz del servicio que hemos importado (Heroe).
Por último, en la función "ngOnInit" (que es una función que se ejecuta automáticamente una vez que se haya construido el componente, es decir, después del constructor) hemos indicado que la propiedad "heroes" del componente va a ser igual a la propiedad "heroes" del servicio. Es en ésta línea donde estamos pasando la información del servicio al componente.

Una vez modificada la clase del componente, vamos a modificar su código html ("heroes.component.html") para mostrar los datos recibidos del servicio.
Vamos a utilizar la directiva *ngFor para que aparezca una tarjeta por cada elemento del array "heroes" del componente:


Y éste sería el resultado al levantar la aplicación:


Y eso sería todo.

Como último apunte, aquí hemos creado el servicio de forma manual, pero al igual que ocurre con los componentes, los servicios pueden ser creados mediante línea de comandos. En la consola de comandos, nos situamos dentro del proyecto y ejecutamos el siguiente código:

ng g s services/heroes

Este código tendría el mismo efecto que crear los ficheros a mano. El comando se puede traducir como "ng generate service services/heroes", donde "services/heroes" es la ruta donde va a crearlo.

martes, 4 de septiembre de 2018

Angular: 8. Rutas de navegación de la aplicación

Vamos a mostrar cómo configurar las rutas de navegación para que, cuando accedamos a las diferentes secciones del menú de navegación, se cargue el contenido de cada sección sin recargar el resto de la página.

Primero debemos crearnos un fichero nuevo dentro de la carpeta "app". Lo llamaremos "app.routes.ts" y nos servirá como fichero configurador de rutas:



Lo informamos con el siguiente contenido:


Como se ve en el fichero, primero importamos todos los componentes que tendrá nuestro menú, que coincidirán con las secciones del menú.
Después configuramos una constante "APP_ROUTES" que asignará un nombre de ruta a cada componente, con una ruta final por defecto (la que cargará al entrar por primera vez en la aplicación o si entramos en una ruta no válida) que llevará, en este caso, al nombre de ruta "home".

Después, modificamos el fichero "app.module.ts" para importar el fichero de rutas como se ve en la imagen:


A continuación, configuramos el html de nuestro menú para que cada opción de menú llame a una ruta distinta mediante la etiqueta "[routerLink]". Los nombres de las rutas que indicamos en esas etiquetas coinciden con los que les dimos en el fichero "app.routes.ts":


Por último, en el fichero "app.component.html", que es donde definimos los elementos de la página, creamos un contenedor div y dentro incluimos la etiqueta "router-outlet":


La etiqueta "router-outlet" es la etiqueta donde se va a cargar el contenido de la ruta en la que estemos en éste momento. Es el contenido de la página que se va a ir sustituyendo a medida que vayamos navegando por el menú. Lo hemos incluido dentro de una etiqueta div que servirá de contenedor.
Al inicio del documento y fuera del contenedor tenemos la etiqueta "app-navbar", que es el menú de la aplicación. Está fuera del contenedor porque el propio menú no debe recargarse al cambiar de ruta. Podemos pensar que el fichero "app.component.html" es el "marco" de la aplicación y que la etiqueta "router-outlet" es el "contenido" de la misma que se va modificando a medida que navegamos por la aplicación.

Una vez echas todas estas modificaciones, podemos comprobar que funciona correctamente:




Y eso es todo.