El Gran Libro De Angular 14o3u

  • ed by: Anonymous WNN7Hujl
  • 0
  • 0
  • May 2021
  • PDF

This document was ed by and they confirmed that they have the permission to share it. If you are author or own the copyright of this book, please report to us by using this report form. Report l4457


Overview 6h3y3j

& View El Gran Libro De Angular as PDF for free.

More details h6z72

  • Words: 66,069
  • Pages: 456


18

El gran libro de Angular



app.js: En este archivo tenemos denido el módulo y la directiva de tipo “entidad” a los que se hacía referencia en el index.html. (function() { var app = angular.module(‘testAngularJS’, []); app.directive(‘entityDirective1’, function() { return { restrict: ‘E’, template: ‘

{{title}} 49413a

’, scope: {}, link: function(scope, element){ scope.title=’AngularJS: Hola mundo!!’; } }; }); })();

Ejemplo Angular. Aparte de los archivos indicados a continuación, el proyecto incluye muchos otros archivos relacionados con la carga de bibliotecas necesarias y el uso de TypeScript. En la imagen anterior puede ver algunas de estas dependencias referenciadas en el archivo package.json de un proyecto Angular. •

index.html: … Loading...



app.component.ts: Denición del componente usado en el index.html. import { Component } from ‘@angular/core’;

@Component({ selector: ‘app-root’, template: ‘

{{title}} 49413a

’, styleUrls: [‘./app.component.css’] }) export class AppComponent { title = ‘Angular: Hola mundo!!!!’; }

El gran libro de Angular

19

004

Instalación

Para trabajar con Angular necesitamos realizar diversas instalaciones, algunas de las cuales son imprescindibles, como por ejemplo Node.js, y otras son opcionales, aunque recomendadas, ya que nos facilitarán enormemente el trabajo. Por ejemplo, el puede utilizar el editor que más le guste, pero recomendamos emplear algunos editores que aportan un sinfín de utilidades a la hora de comprobar la sintaxis de nuestras sentencias o de aportar bloques de código a modo de plantilla.

Importante Procure instalar la última versión de los productos indicados para mantenerse actualizado y disfrutar de las últimas actualizaciones en todo momento.

1. En primer lugar instalaremos Node.js. Para ello podemos descargarlo desde la siguiente página: https://nodejs.org/es// En esta página, seleccionaremos la opción que más nos interese según nuestro SO y el número de bits (32 o 64). En nuestro caso, seleccionamos la opción Windows Installer (.msi) 64-bit y descargamos el instalador en una carpeta desde la que realizaremos posteriormente la instalación. Una vez descargado, ejecutaremos el instalador y podemos aceptar todos los valores que nos propone por defecto hasta que lleguemos a la pantalla nal y pulsemos Finish. 2. Seguidamente, instalaremos TypeScript. Para ello, podemos acudir al siguiente link: https://www.typescriptlang.org/

20

El gran libro de Angular

Al pulsar sobre el botón aparece una pantalla en la que se muestra la sentencia a ejecutar para instalar TypeScript npm install -g typescript A continuación, copiaremos dicha sentencia y abriremos una ventana de CMD (Ejecutar->CMD) para pegarla y ejecutarla. 3. A continuación, instalaremos Angular-Cli. Para ello, acudiremos a la siguiente página: https://cli.angular.io/ En dicha página, ya podemos ver diversas instrucciones entre las que hallamos la siguiente:

npm install -g @angular/cli

De nuevo, abrimos una ventana CMD (Ejecutar->CMD) y ejecutaremos la sentencia anterior. Para obtener más información sobre los detalles de la instalación y prerrequisitos, puede consultar la siguiente página: https://github.com/angular/angular-cli 4. Podemos realizar nuestras pruebas en muchos navegadores, pero nosotros realizaremos todas las explicaciones basándonos en Google Chrome y en sus herramientas para desarrolladores. Por tanto, sugerimos que utilice este navegador, el cual puede descargar de la siguiente página: https://www.google.es/chrome/browser/desktop/index.html 5. Por último, tal y como hemos indicado en la introducción, necesitará un editor que le ayude a desarrollar sus componentes con Angular y puede utilizar alguno de los siguientes: Atom

https://atom.io/

Visual Studio Code

https://code.visualstudio.com/

Sublime Text

https://www.sublimetext.com/3

El gran libro de Angular

21

Nosotros utilizaremos Atom en nuestras explicaciones y, en este caso, una vez instalado Atom, recomendamos añadir una serie de funcionalidades que nos facilitarán el desarrollo con Angular. Para añadir funcionalidades, accederemos a Help->Welcome Guide y, seguidamente, accederemos a Install a Package->Open Installer. Cuando aparezca la pantalla de Install Packages, teclearemos el nombre del paquete que queramos añadir y, una vez que nos muestre el package deseado, pulsaremos sobre Install.

Algunas de las funcionalidades recomendadas se hallan en los siguientes packages: • • • • • • • •

22

Angular-2-TypeScript-Snippets, Angular2-Snippets, Atom-Bootstrap 3, Atom-TypeScript, le-icons, Linter, Linter-UI-Default, PlatformIO-IDE-Terminal.

El gran libro de Angular

005

TypeScript. Introducción (variables, clases, transpilación, etc.) TypeScript es un lenguaje de programación orientado a objetos fuertemente tipado que se traduce a JavaScript añadiéndole características que no posee. La operación de traducir TypeScript a JavaScript se conoce como transpilación. Gracias al uso de TypeScript, es posible localizar errores de sintaxis antes incluso de su ejecución. De ahí que haya ganado mucha aceptación entre los desarrolladores del mundo web.

Importante TypeScript permite desarrollar un código con menos errores y aprovechar toda la potencia de una programación orientada a objetos.

Podríamos dedicar un libro completo a TypeScript, pero, en este ejercicio, simplemente ofreceremos una pincelada sobre el lenguaje y elaboraremos el clásico programa Hola Mundo para que podamos ver cómo se compila y ejecuta. Los programas escritos con TypeScript se suelen escribir en cheros con la extensión ts. Una vez escritos, dichos programas se transpilan (compilan) o, lo que es igual, se traducen a JavaScript para que puedan ejecutarse posteriormente. Cualquier instrucción escrita en JavaScript “puro” se copia igual (sin traducción) en el chero resultante de la transpilación. Para compilar usaremos el comando TSC y para ejecutar emplearemos el comando node, como veremos más adelante y el cual ya hemos instalado en capítulos anteriores. La sintaxis que hallaremos en TypeScript está compuesta por módulos, funciones, variables, sentencias, expresiones y comentarios. Respecto de las funciones, TypeScript permite denir funciones con nombre, anónimas, tipo Lambda o de echa, además de permitir la sobrecarga de funciones utilizando diferentes parámetros y/o tipos en sus llamadas. Asimismo, disponemos de un gran surtido de operadores, sentencias condicionales, loops, funciones y métodos para numéricos y strings. El gran libro de Angular

23

También es posible denir interfaces y clases, incluyendo en las mismas campos, constructores y funciones utilizando la herencia y encapsulación propias de POO.

Para acabar con la breve mención al lenguaje, es importante resaltar que el concepto de namespace permite organizar mejor el código y sustituye a los antiguos Internal Modules. A continuación, vamos a crear un programa con TypeScript que simplemente muestre el texto Hola Mundo: 1. Para ello, nos ubicaremos en nuestro directorio de ejercicios (Ej100_ angular) y crearemos el directorio 005_HolaMundo_TS. 2. Seguidamente, abriremos nuestro editor favorito y, dentro del directorio recién creado, crearemos el chero 005_HMTS.ts con el siguiente contenido:

24

El gran libro de Angular

var texto:string=”Hola Mundo” console.log(texto) 3. Una vez creado y guardado el chero, accederemos a la ventana de CMD y nos ubicaremos en nuestro nuevo directorio (005_HolaMundo_TS) para teclear lo siguiente:

tsc 005_HMTS.ts 4. Observaremos que, si no se ha producido ningún error, la compilación se realiza de forma silenciosa devolviendo el control al prompt de la ventana de CMD. 5. En este punto, procederemos a la ejecución de nuestro programa tecleando lo siguiente: node 005_HMTS 6. Observaremos como, efectivamente, se muestra el texto Hola Mundo en pantalla.

El gran libro de Angular

25

006

Denición de elementos en una aplicación

En el capítulo de introducción, enumeramos los elementos que había que tener en cuenta en Angular. A continuación, los deniremos brevemente. Elemento

Comentario

Módulo

Conjunto de códigos dedicados a resolver un objetivo que generalmente exporta una clase. Cada aplicación posee al menos una clase de módulo que denominamos “módulo raíz” y que, por defecto, posee el nombre de AppModule. En el mismo podemos apreciar una clase con un decorador (@NgModule) y una serie de propiedades entre las que destacamos las siguientes: • • • • •

Declarations: dene las vistas que pertenecen a este módulo. Exports: declaraciones que han ser visibles para componentes de otros módulos. Imports: clases que otros módulos exportan para poderlas utilizar en el módulo actual. Providers: servicios usados de forma global y accesibles desde cualquier parte de la aplicación. Bootstrap: la vista principal o componente raíz, que aloja el resto de vistas de la aplicación. Propiedad establecida solo por el módulo raíz.

Un módulo puede agrupar diversos componentes relacionados entre sí.

26

El gran libro de Angular

Componente

Elemento que controla una zona de espacio de la pantalla que representa la “vista”. Dene las propiedades y métodos que usa el propio template y contiene la lógica y la funcionalidad que utiliza la vista. Pueden tener atributos tanto de entrada (decorador @ Input) como de salida (decorador @Output). También podemos denir al componente como: Componente = template + metadatos + clase

Template

Dene la vista de un Componente mediante un fragmento de HTML.

Metadatos

Permiten decorar una clase y congurar así su comportamiento. Extiende una función mediante otra sin tocar la original.

Data binding

Permite intercambiar datos entre el template y la clase del componente que soporta la lógica del mismo. Existen 4 tipos de Data binding (que analizaremos en profundidad más adelante) y que son: • • •



Interpolación: muestra el valor de una propiedad en el lugar donde se incluya {{ propiedad }}. Property binding: traspaso del objeto del componente padre al componente hijo ([objHijo]=“objPadre”). Event binding: permite invocar un método del componente pasándole un argumento al producirse un evento (p. ej., (click)=“hazAlgo(obj)”). Two-way binding: binding bidireccional que permite combinar event y Property binding (p. ej., input [(ngModel)]= “obj”).

Directiva

Permite añadir comportamiento dinámico a HTML mediante una etiqueta o selector. Existen directivas estructurales (*ngFor o *ngIf) o de atributos que modican el aspecto o comportamiento de un elemento DOM (NgSwitch, NgStyle o NgClass).

Servicio

Son clases que permiten realizar acciones concretas que ponen a disposición de cualquier componente. Por ejemplo, permiten obtener datos, resolver lógicas especiales o realizar peticiones a un servidor.

Permite suministrar funcionalidades, servicios, etc., a un componente Dependency sin que sea el propio componente el encargado de crearlos. Utiliza injection el decorador @Injectable(). Generalmente proporciona servicios y facilita los test y la modularidad del código.

El gran libro de Angular

27

Al crear una aplicación, por defecto se crea el módulo app.module.ts, como veremos en ejercicios posteriores. En el mismo, podemos apreciar diferentes partes correspondientes a:

Importante Cree módulos para separar los grupos de componentes que dan soporte a una lógica determinada y que pueden reutilizarse en diversas aplicaciones.



Los “imports”: • BrowserModule: usado para renderizar la aplicación en el navegador. • NgModule: decorador necesario para el módulo. • AppComponent: componente principal del módulo.



Al decorador @NgModule con su metadata: • Declarations: AppComponent (vista del módulo por defecto). • Imports: BrowserModule (clase necesaria para el navegador). • Providers: en este caso, no disponemos de ninguno. • Bootstrap: AppComponent (componente principal). A su clase: permite cargar la aplicación (AppModule).



El archivo total agrupa todas las partes descritas que constituyen el módulo en sí mismo.

28

El gran libro de Angular

007

Denición de un componente

Un componente es una clase a la que se le añade un decorador (@Component) y que permite crear nuevas etiquetas HTML mediante las cuales podemos añadir funcionalidad a nuestras páginas controlando determinadas zonas de pantalla. Básicamente, los componentes se organizan en forma de árbol teniendo un componente principal donde, por defecto, su propiedad “selector” posee el valor app-root, gracias al cual el componente puede incluirse en nuestras páginas HTML (p. ej., en index.html) mediante el tag como veremos más adelante.

Los componentes se componen de tres partes: •

Anotaciones: metadatos que agregamos a nuestro código y que permite denir ciertas propiedades como son:

El gran libro de Angular

29

• • • • • • • • •

Selector: nombre a utilizar como tag en HTML para indicar a Angular que cree una instancia del componente cuando se encuentre con dicho tag. Template: plantilla a utilizar para el componente y que se describe en el propio chero ts del mismo. TemplateUrl: indica el URL en el que se halla la plantilla en caso de denirse externamente. Style: denición de estilos para la plantilla. StyleUrl: array que contiene los diferentes archivos de estilos que pueden utilizarse en el componente en curso. Host: permite encapsular ciertas partes del componente. Directive: array con las directivas que pueden utilizarse en el componente. Input: dene variables que recogen información del padre. Output: dene variables que pasan información al padre.



Vista: contiene el template que usaremos para elaborar la pantalla asociada al componente. Esta pantalla podemos denirla en un archivo auxiliar o bien dentro del propio archivo donde denimos la clase controlador encerrando el código HTML entre apóstrofos (`

{{title}} 49413a

`).



Controlador: clase que contendrá la lógica del componente (deniciones, funciones, etc.)

Generalmente, un componente suele llevar asociados diversos archivos con el siguiente cometido: •

app.component.html: contiene el código HTML mediante el que fabricamos la pantalla (o Vista).



app.component.css: dene los estilos que usaremos en la vista del componente.



app.component.ts: archivo que contiene la lógica del componente (Controlador) y que se escribe en TypeScript para ser traducido a JavaScript posteriormente.



app.component.spec.ts: archivo usado para la realización de test unitarios.

En ejercicios posteriores, veremos que, al generar una aplicación con determinadas utilidades (p. ej., Angular-CLI), se crea un componente por defecto con una serie de bloques como los que se han descrito, cuyo código es similar al siguiente: 30

El gran libro de Angular

Importante Cree tantos componentes como pantallas necesite y compártalos entre módulos para reutilizarlos.

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

@Component({ selector: ‘app-root’, templateUrl: ‘./app.component.html’, styleUrls: [‘./app.component.css’] })

export class AppComponent { title = ‘007 Componentes’; } Veremos también cómo se crea cada uno de los archivos mencionados anteriormente con un contenido por defecto.

Recuerde que el objetivo del componente es gestionar la vista. Por tanto, si necesita escribir mucha lógica, es mejor plantearse elaborar un servicio donde ubicarla. Cuando se analice el ciclo de vida de un componente, veremos que es posible realizar ciertas inicializaciones al crear el componente en el método ngOninit. Un componente puede tener atributos de entrada y/o de salida para intercambiar información con otros componentes padres e hijos. Dichos atributos requerirán del uso de las directivas @Input() y @Output().

El gran libro de Angular

31

008

Metadata - denición

Importante Cada decorador posee su metadata para denir el comportamiento del elemento asociado (módulo, componente, etc.).

Los metadatos permiten congurar el comportamiento de una clase a la que se le ha asociado un decorador. En función del decorador asociado, los metadatos varían y denen características diferentes. Por ejemplo, una clase no se trata como un componente hasta que no se le asocia el decorador @Component con su metadata necesaria. Los decoradores más comunes son @ Component y @Injectable Como recordará, hablamos de metadatos cuando presentamos los módulos y componentes en los primeros ejercicios de este libro.

A continuación, se muestra una relación de propiedades asociadas a una serie de decoradores, así como el módulo que hay que importar para su utilización: Decorador

Propiedades metadata

Módulo a importar

@Input @Output

bindingPropertyName: string bindingPropertyName: string

Input Output

@Attribute

attributeName: string

Attribute

@Hostlistener

args: string[]

HostListener

@HostBinding

eventName: string hostPropertyName: string

HostBinding

@Component

animations: any[]

Component

changeDetection: ChangeDetectionStrategy encapsulation: ViewEncapsulation entryComponents: Array |any[]> interpolation: [string, string] moduleId: string styles: string[] styleUrls: string[] template: string templateUrl: string viewProviders: Provider[] 32

El gran libro de Angular

@Directive

exportAs: string

Directive

host: {[key: string]: string} inputs: string[] outputs: string[] providers: Provider[] queries: {[key: string]: any} @Host

selector: string -

Host

@Inject @Injectable

token: any -

Inject Injectable

@NgModule

bootstrap:

NgModule

Array |any[]> declarations: Array |any[]> entryComponents: Array |any[]> exports: Array |any[]> id: string imports: Array |ModuleWithProviders|any[]> providers: Provider[] schemas: Array<SchemaMetadata|any[]> @Optional

-

Optional

@Pipe

name: string

Pipe

@Self

pure: boolean -

Self

@SkipSelf

-

SkipSelf

En los próximos ejercicios veremos muchos ejemplos de metadata asociados a módulos, componentes y directivas. A continuación, describimos las propiedades más importantes:

El gran libro de Angular

33



Animations: lista de animaciones del componente.



Bootstrap: dene los componentes que deberían tenerse en cuenta en el arranque cuando este módulo es Bootstrap.



ChangeDetection: estrategia de detección de cambios utilizada por el componente.



Declarations: lista de directivas/pipes pertenecientes al módulo.



Encapsulation: estrategia de encapsulación de estilo usada por el componente.



EntryComponents: lista de componentes que deben compilarse cuando se dene este módulo.



ExportAs: nombre usado para exportar la instancia del componente en una plantilla.



Exports: lista de directivas, pipes y módulos que pueden usarse en otros componentes que tengan importado el módulo en curso.



Host: mapa de propiedad de clase para enlaces de elementos de host para eventos, propiedades y atributos.



Id: usado para identicar módulos en getModuleFactory.



Imports: lista de módulos cuyas directivas/pipes exportadas pueden utilizarse en el módulo.



Inputs: lista de nombres de propiedades de clase para enlazar datos como entradas de componentes.



Interpolation: marcadores de interpolación personalizados utilizados en la plantilla del componente.



ModuleID: ID del módulo ES/CommonJS del archivo donde se dene el componente.



Outputs: lista de nombres de propiedades de clase que exponen eventos de salida a los que otros pueden suscribirse.



PreserveWhitespaces: permite mantener o eliminar espacios en blanco.



Providers: dene el conjunto de objetos inyectables disponibles en el módulo para este componente y sus hijos.

34

El gran libro de Angular



Queries: consultas que pueden inyectarse en el componente.



Schemas: usado para declarar elementos y propiedades que no son componentes ni directivas Angular.



Selector: tag con el que se identica el componente en una plantilla.



Styles: estilos “en línea” que hay que aplicar a la vista del componente.



StyleUrls: lista de URL con hojas de estilo que pueden aplicarse a la vista del componente.



Template: plantilla “en línea” aplicada a la vista del componente.

•

TemplateUrl: URL que apunta al archivo que contiene la vista del componente.



ViewProviders: lista de proveedores disponibles para el componente e hijos.

El gran libro de Angular

35

009

Hola Mundo (Manual)

A continuación, mostraremos cómo fabricar una aplicación “mínima” que nos permita mostrar una página sencilla en la que se muestre el texto ‘Hola Mundo (by TwoBy2)’. En sucesivos ejercicios veremos una forma más sencilla y eciente de hacer lo mismo (usando Angular-Cli), pero consideramos interesante mostrar cómo hacer manualmente lo mismo para que podamos valorar mejor otras utilidades.

Importante Instale Node.js y, una vez creados los cheros mínimos descritos, instale las dependencias.

1. En primer lugar, instalaremos Node.js (si aún no lo hemos hecho). Por favor, revise el ejercicio 004 dedicado a la instalación.

2. Seguidamente, crearemos el directorio 009_HolaMundoManual. Para ello, abriremos una ventana de CMD y teclearemos: >cd C:\Ej100_angular >mkdir 009_HolaMundoManual

36

El gran libro de Angular

3. A continuación, dentro de este directorio, crearemos los siguientes cheros utilizando el editor que deseemos (p. ej., Atom): •

tscong.json: compilación utilizada por el compilador de TypeScript.



typings.json: identica deniciones de TypeScript que hagan falta.



package.json: permite denir las dependencias del proyecto.

4. Seguidamente, instalaremos las dependencias del proyecto. Para ello, nos ubicaremos en el directorio C:\Ej100_angular\009_HolaMundoManual y ejecutaremos npm install:

El gran libro de Angular

37

>cd C:\Ej100_angular\009_HolaMundoManual >npm install

5. Crearemos el directorio app (C:\Ej100_angular\009_HolaMundoManual\app): >cd C:\Ej100_angular\009_HolaMundoManual >mkdir app

6. Dentro del directorio app crearemos los siguientes cheros: • •

app.component.ts: permite denir un componente. main.ts: permite cargar el componente raíz lanzando el framework.

7. El último chero que se creará será el chero index.html en el directorio raíz (C:\Ej100_angular\009_HolaMundoManual\index.html): 8. Finalmente, ejecutaremos npm start y observaremos el resultado en nuestro navegador.

38

El gran libro de Angular

010

Comandos básicos. Hola Mundo (Angular CLI)

Angular CLI es una herramienta que permite crear aplicaciones Angular desde el terminal apoyándose en plantillas de código que, además de normalizar los desarrollos, agilizan la fabricación de todo tipo de elementos como puede ser los componentes, los servicios y los pipes que veremos más adelante. CLI signica command line interface (interfaz de línea de comando) y, como su nombre indica, permite lanzar comandos desde un terminal para crear elementos de Angular. Entre las funcionalidades que obtendremos al usar Angular CLI destacan las siguientes: • • • •

Importante Utilice Angular CLI siempre que le sea posible porque apreciará el trabajo que la utilidad realiza por usted no solo creando elementos en base a templates, sino también incorporando referencias e imports en los cheros de conguración que lo requieren.

Herramientas para testing. Herramientas para despliegue. Servidor HTTP para lanzar el proyecto. Sistema live-reload que permite replicar de forma inmediata en el navegador cualquier cambio detectado en el proyecto.

En el capítulo de instalación, ya mencionamos cómo instalar Angular CLI, pero, a modo de recordatorio, adjuntamos la sentencia necesaria para la misma:

npm install -g angular-cli

La opción -g nos permite realizar la instalación de forma global, lo que signica que podemos usarla desde cualquier lugar. Al nal de la instalación, observaremos que el cursor se coloca de nuevo en el prompt de la ventana CMD, esperando alguna acción. El gran libro de Angular

39

A partir de este momento, podemos realizar una serie de acciones que se ejecutarán mediante el comando ng seguido de alguna palabra clave u opción.

Por ejemplo, podemos empezar a probar la ayuda con ng -- help. Los comandos más importantes son los siguientes: Comando

Descripción

help

Invoca a la ayuda.

new

Permite crear una nueva aplicación.

serve

Construye la aplicación y arranca el servidor web.

generate

Permite generar los siguientes elementos: class, component, directive, enum, guard, interface, module, pipe, service, etc.

lint

Permite usar tslint (herramienta que permite revisar el código durante su edición).

Test

Permite generar un directorio de salida para pruebas.

e2e

Sirve la aplicación y ejecuta pruebas.

build

Compila la aplicación en un directorio de salida.

get/set

Obtiene/establece un valor de la conguración.

doc

Abre la documentación ocial Angular para buscar información sobre la palabra indicada.

40

El gran libro de Angular

eject

Permite extraer el archivo de conguración de webpack.

xi18n

Extrae los mensajes i18n de las plantillas.

A continuación, vamos a crear un proyecto con Angular CLI para fabricar el clásico Hola Mundo. 1. Para ello, abriremos una ventana de CMD y nos situaremos en el directorio C:\Ej100_angular para teclear el siguiente comando:

C:\Ej100_angular>ng new HMAC





•



Observaremos que, al nal de la creación, aparece un mensaje que indica que el proyecto se ha creado satisfactoriamente. Seguidamente, abriremos el proyecto con nuestro editor (p. ej., en Atom bastará con arrastrar la carpeta del proyecto sobre el propio Atom y se abrirá el proyecto completo). Una vez abierto el proyecto, modicaremos el archivo app.component.ts ubicado en HMAC/ src/app y a la variable title le asignaremos el valor ‘Hola Mundo Angular CLI’. Podemos modicar también el chero html que se crea por defecto ubicado en HMAC/ src/app/app.component.html para dejarlo simplemente con el siguiente contenido:

{{title}}! 2s4ff



2. Una vez salvado el archivo, pasaremos a ejecutar la aplicación (utilizando el comando serve) accediendo al directorio del proyecto y tecleando lo siguiente: C:\Ej100_angular>cd HMAC C:\Ej100_angular\HMAC>ng serve

El gran libro de Angular

41

3. Observaremos que, tras una serie de mensajes, la aplicación arranca y recibimos un mensaje indicando que la compilación se ha realizado satisfactoriamente.

4. Por último, abriremos nuestro navegador y comprobaremos el resultado tras acceder al siguiente URL: http://localhost:4200/

42

El gran libro de Angular

011

Elementos que se pueden crear con Angular CLI (Component, Directive, etc.)

Tal y como comentamos en el ejercicio anterior, una de las acciones que podemos realizar con Angular CLI es crear diferentes tipos de elementos e integrarlos con nuestra aplicación de forma automática. Para ello, usaremos el subcomando generate (ng generate o ng g en modo abreviado) seguido del tipo de elemento que deseamos crear y una serie de opciones. La sintaxis general es: ng generate tipo_elemento nombre_elemento opciones

Importante Siempre que pueda utilice ng generate para crear elementos ya que, además de crearlos con una plantilla, se insertan las referencias de forma automática, lo que facilita mucho el trabajo.

Es recomendable utilizar nombres sencillos, ya que los elementos que se crean automáticamente utilizan dicho nombre para añadirles alguna partícula o extensión según cada caso. Una de las ventajas de utilizar ng es que la utilidad se encarga de incluir las referencias a los nuevos elementos donde sea necesario como, por ejemplo, incluir el import y las declarations del elemento en el chero app.module.ts si procede. Los distintos elementos que podemos crear son los siguientes: Elemento

Abreviación

Comentario

Component

ng g c

ng g component nomComponente Es el principal elemento mediante el cual construimos los elementos y la lógica de la página.

Directive

ng g d

ng g directive nomDirectiva Permite añadir comportamiento dinámico a HTML (estructurales y de atributos).

Pipe

ng g p

ng g pipe nomPipe Genera una salida transformando un dato obtenido desde la entrada.

El gran libro de Angular

43

Service

Class

ng g s

ng g cl

ng g service nomServicio Son clases complementarias a los componentes que permiten realizar cierta lógica o acciones como puede ser proporcionar datos a los componentes o realizar peticiones al servidor, etc. ng g class nomClase Añade una clase a la aplicación.

Guard

ng g guard nomGuard Añade funciones que permiten controlar o activar ciertas rutas.

Interface

ng g interface nominterface Añade interfaces a la aplicación (contratos que otras clases han de cumplir para utilizarlos).

Enum

ng g e

ng g enum nomEnum Genera una enumeración.

Module

ng g m

ng module nomModulo Elemento que permite agrupar componentes, servicios, directivas, etc., para crear una aplicación.

A continuación, mostramos algunas opciones: --at

Permite crear el elemento sin crear un nuevo directorio.

--route=

Indica la ruta principal. Solo se utiliza para generar componentes y rutas.

--skip-routergeneration

No crea la conguración de la ruta. Solo se emplea para generar rutas.

--default

Indica que la ruta debe ser la predeterminada.

--lazy

Indica que la ruta es “lazy” (carga los componentes cuando se necesitan).

-is

inline css. Evita la creación de un chero css.

-it

inline html. Evita la creación de un chero html.

44

El gran libro de Angular

Para comprobar el funcionamiento de generate, simplemente crearemos una aplicación a la que le añadiremos un componente y al que no daremos ningún uso, pero que nos permitirá observar qué cheros se crean durante el proceso. 1. En primer lugar, abriremos una ventana de CMD y nos situaremos en la carpeta Ej100_angular. 2. Seguidamente, crearemos una nueva aplicación con el comando ng new y la renombraremos para añadirle el número de ejercicio: ng new EjemGenerate rename EjemGenerate 011_EjemGenerate

3. A continuación, nos ubicaremos en el directorio recién creado para la nueva aplicación y crearemos un componente con la siguiente sintaxis:

ng generate component componentes/compo1

4. Podíamos haber utilizado la sintaxis abreviada: ng g c componentes/compo1 5. Fíjese que al haber indicado componentes/compo1, nos ha creado de paso la carpeta componentes bajo el directorio src/app para que podamos almacenar todos los componentes que creemos en la misma carpeta, de forma que quede más organizado. El gran libro de Angular

45

6. Si abre el proyecto en su editor (p. ej., Atom), observará los cheros que se han creado por defecto.

7. Si analizamos el chero app.module.ts, apreciaremos que se han añadido de forma automática el import del componente y su referencia en el apartado declarations.

46

El gran libro de Angular

012

Descripción de un proyecto

Al crear un proyecto, por defecto se crean una serie de carpetas y cheros que son la base de nuestra aplicación y que iremos completando según la funcionalidad que queramos dar a la misma.

Importante Mantenga organizada la estructura creando carpetas para almacenar los diferentes tipos de elementos que necesite. Por ejemplo, cree una carpeta de componentes para incluir components, otra para servicios y así sucesivamente.

Para analizar la estructura de una aplicación podemos utilizar alguna de las creadas en ejercicios anteriores como por ejemplo la que creamos para mostrar cómo utilizar ng generate para crear un componente (011_EjemGenerate). Así pues, abrimos dicha aplicación con nuestro editor (p.e. Atom) y observamos la siguiente estructura:

Elemento

Comentario

.git

Contiene los archivos necesarios para la gestión con GIT.

e2e

Carpeta que contiene los archivos de prueba, denominados end to end (de extremo a extremo) que se ejecutan con Jasmine.

node_modules

Contiene todos los paquetes y dependencias de Node.js de nuestro proyecto.

src

Carpeta que contiene los archivos fuentes raíz de la aplicación.

.editorcong

Contiene la conguración de nuestro editor.

.gitignore

Permite indicar archivos que queremos ignorar de cara al control de versiones git.

angular-cli. json

Contiene la conguración de CLI.

karma.conf.js

Contiene la conguración para los test.

package.json

Describe las dependencias necesarias para ejecutar la aplicación.

p r o t r a c t o r. conf.js

Conguración de test con Jasmine.

El gran libro de Angular

47

REE.md

‘Ree’ clásico de cualquier proyecto compartido en GitHub.

tslint.json

Contiene la conguración del Linter para Typescript.

La carpeta src es una de las más importantes puesto que es donde iremos incluyendo nuestros componentes, servicios y resto de elementos de nuestra aplicación. Si la expandimos, podemos observar lo siguiente:

Elemento

Comentario

app

Carpeta raíz que contendrá los componentes, servicios y resto de elementos que constituyen nuestra aplicación.

assets

Imágenes, vídeos y archivos en general que no son propiedad de ningún componente.

environments

Contiene características relativas al entorno de trabajo.

favicon.icon

Imagen que permite identicar nuestra aplicación.

index.html

Archivo raíz donde se inicia la aplicación

main.ts

Es el primer archivo que se ejecuta y contiene todos los parámetros de la aplicación.

polylls.ts

Asegura la compatibilidad con los navegadores.

styles.css

Estilos del proyecto.

test.ts

Puede contener test unitarios.

tscong.json

Conguración de TypeScript.

48

El gran libro de Angular

El gran libro de Angular

49

013

Módulos: Creación

Los módulos son clases que nos permiten organizar nuestra aplicación encapsulando funcionalidades concretas dentro de los mismos. Son agrupadores de componentes, pipes, directivas, etc., relativos a una funcionalidad que permiten crear bloques reutilizables. Utilizan el decorador @NgModule que permite añadir metadata. Los metadatos contienen: • • • • •

Importante Cuando la aplicación se amplía es mejor crear diferentes módulos para organizar mejor las funcionalidades y permitir que las cargas se realicen cuando realmente sean necesarias (lazy loading).

Declarations: declaración de componentes, directivas, pipes, etc. Exports: exportación de clases para poderlas compartir con otros componentes. Imports: importación de otros módulos que ofrecen clases usadas en nuestro módulo. Providers: carga servicios para toda la aplicación y permite que estos se pasen al resto de componentes por inyección de dependencias. Bootstrap: dene el componente principal para el arranque y se utiliza en el módulo principal (root module).

Como mínimo, siempre existe un módulo ya que, al crear una aplicación, se crea el módulo root, el cual permite que la aplicación se lance, pero este módulo lo analizaremos en detalle en el próximo ejercicio. Existen módulos que, a su vez, son librerías de módulos, como ocurre con el propio Angular, que ofrece librerías asociadas a paquetes npm y que permiten realizar importaciones selectivas según nuestras necesidades. Por ejemplo, Angular posee librerías que son módulos como FormsModule, HttpModule o RouterModule. Al igual que las clases, los módulos pueden exportar u ocultar componentes, servicios, etc. Podemos crear módulos a mano, pero, por facilidad, recomendamos hacerlo con Angular CLI y, en este caso, los módulos se crean usando el comando generate de la siguiente manera:

50

El gran libro de Angular

ng generate module mimodulo Al crear el módulo, por defecto suceden dos cosas: • •

Se crea el directorio src/app/mimodulo. Se crea el archivo src/app/mimodulo/mimodulo.module.ts, con la denición del propio módulo MimoduloModule dentro.

Las opciones disponibles son: app

--app (aliases: -a) default value: 1st app Especica el nombre o índice de la aplicación a utilizar. El índice hace referencia al orden de la app dentro del array asociado a “apps” en angular-cli.json. Por defecto, usa la primera app.

at

--at Si se indica –at, no se crea un directorio.

module

--module (aliases: -m) Especica dónde se debe importar el módulo. Por ejemplo, si estamos creando mod3 y añadimos la opción --module mod2, se importaría el módulo recién creado en mod2.

spec

--spec Si se indica –spec, se crea el archivo mimodulo.module.spec.ts.

routing

--routing Si se indica –routing, se crea el archivo mimodulo-routing. module.ts. (archivo de módulo de enrutamiento).

A continuación, crearemos una aplicación para añadirle posteriormente un par de módulos y analizar la estructura asociada a los mismos. 1. En primer lugar, nos ubicaremos en ej100_angular y crearemos el proyecto modCrea mediante el comando ng new: C:\Ej100_angular>ng new modCrea

El gran libro de Angular

51

2. Seguidamente, renombraremos el proyecto para que haga referencia a nuestro número de ejercicio. Para ello, estando ubicados en el directorio Ej100_angular, escribiremos lo siguiente: C:\Ej100_angular>rename modCrea 013_modCrea

3. Ahora, abrimos nuestro proyecto con nuestro editor (en nuestro caso, usamos Atom) y observamos la estructura del proyecto poniendo el foco en la carpeta app.

4. A continuación, ubicados en 013_modCrea, crearemos el módulo mod1 tecleando lo siguiente : C:\Ej100_angular>cd 013_modCrea C:\Ej100_angular\013_modCrea>ng generate module mod1

5. Si analizamos la estructura, vemos que dentro de app ha creado una carpeta denominada mod1 y dentro de la misma, un archivo denominado mod1. module.ts con la clase Mod1Module y el decorador @NgModule.

52

El gran libro de Angular

6. Ahora, crearemos un segundo módulo (mod2) pero esta vez le diremos que no cree ningún directorio para el mismo y que, además, que una vez creado realice la importación en nuestro archivo app.module.ts. La sentencia que habrá que teclear será: ng g m mod2 --at -m app

7. Tal y como habíamos dicho, con –at indicamos que no se cree carpeta para el módulo y con --m app indicamos que realice la importación en el módulo app. Efectivamente, analizando la estructura de la app, vemos que no se ha creado un directorio para mod2 y que se ha realizado el import de Mod2Module en app.module.ts.

El gran libro de Angular

53

014

Módulos: RootModule

Tal y como comentamos en el ejercicio anterior, al crear una aplicación con Angular CLI, se crea un módulo que por convenio se denomina AppModule y se almacena en el archivo app.module.ts, el cual denominamos módulo raíz y que es el que usa la aplicación en el arranque de la misma. La aplicación se inicializa pasando el módulo AppModule como parámetro a Bootstrap en main.ts.

Existen 2 formas de hacer Bootstrap: •

Dinámico: se usa el compilador JIT (Just-in-Time) para compilar la aplicación en el navegador y luego inicializar la aplicación. Veamos cómo queda main.ts con esta opción: import { platformBrowserDynamic } from ‘@angular/platformbrowser-dynamic’; import { AppModule } from ‘./app.module’; platformBrowserDynamic().bootstrapModule(AppModule);



54

Estático: precompila nuestra aplicación antes de enviarla al navegador, con lo que se obtiene una aplicación más pequeña que se carga con rapidez. El tamaño es mucho menor y la velocidad de ejecución más rápida. En este caso, main.ts queda así:

El gran libro de Angular

import { platformBrowser } from ‘@angular/platformbrowser’; import { AppModuleNgFactory } from ‘./app.module. ngfactory’; platformBrowser(). bootstrapModuleFactory(AppModuleNgFactory);

Ambas formas de compilación generan clases de tipo AppModuleNgFactory. Como vemos en nuestro caso, por defecto se usa el siguiente código: platformBrowserDynamic().bootstrapModule(AppModule); Es decir, se usa la compilación dinámica (JIT) y arranca al AppModule descrito anteriormente. Para el análisis de este módulo, utilizaremos el existente en la aplicación creada en el ejercicio anterior (013_Modulos_Creacion). 1. Abrimos el proyecto 013_Modulos_Creacion con nuestro editor (en nuestro caso, Atom) y localizamos el archivo app.module.ts.

2. Al analizar su contenido vemos que el archivo consta de una serie de imports como son BrowserModule y NgModule procedentes de las librerías de Angular y, AppComponent de nuestra propia aplicación. En nuestro ejemplo, importamos Mod2Module porque expresamente habíamos creado el módulo mod2 con la opción –m. Vemos también El gran libro de Angular

55

el decorador @NgModule seguido de su metadata y, por último, de la clase AppModule, la cual exporta para que sea visible por otros elementos de la aplicación. Al entrar un poco más en detalle, obtenemos: Elemento

Comentario

Imports

Importa los elementos que se necesitan en el módulo.

NgModule

Decorador usado con los módulos en Angular y que dene los metadatos que se van a utilizar en el módulo.

BrowserModule

Este módulo se importa solo en el root AppModule y proporciona servicios esenciales para lanzar y ejecutar la aplicación en un navegador.

Declarations

Dene listas de clases view que se van a utilizar (en este caso, AppComponent). Angular utiliza 3 tipos de clases view: componentes, directivas y pipes.

Providers

Servicios accesibles desde todas las partes de la aplicación.

Exports

Dene el subconjunto de declaraciones que estarán disponibles en las plantillas de componentes de otros módulos.

Bootstrap

Dene el componente a llamar al inicializar la aplicación (p. ej., AppComponent). Cuando se lanza la aplicación, expande el template HTML de AppComponent en el DOM, dentro de las etiquetas del elemento existentes en index.html.

3. Metadata, en denitiva, indica a Angular cómo se debe compilar y ejecutar un módulo, además de relacionar los componentes, directivas y pipes incluidos en el mismo.

56

El gran libro de Angular

Importante El arranque de la aplicación se realiza a través del root module que, por convenio, se denomina AppModule y se almacena en el archivo app. module.ts.

015

Componentes: Creación

El componente es el elemento básico del desarrollo en Angular. Una aplicación suele Cree tantos constar de una especie de árcomponentes como bol de componentes de varios necesite para que cada niveles donde un componenuno de ellos muestre la te puede llamar a sus compoparte de información nentes hijos y, a su vez, estos que se requiera en llamar a sus propios hijos (o cada caso. Crearlos con Angular CLI simplica nietos del primero), y así sumucho el trabajo. cesivamente. Un componente, básicamente, es una clase acompañada del decorador @ Component y se encarga de controlar lo que podríamos llamar Vista o zona de pantalla. A grosso modo, un componente está formado por un template, una metadata y una clase. Importante

Según vimos en ejercicios anteriores, al crear una aplicación con Angular CLI, se crea un módulo por defecto y, dentro del mismo, se crea también un componente denominado app.component. El contenido por defecto del mismo es el siguiente: import { Component } from ‘@angular/core’; @Component({ selector: ‘app-root’, templateUrl: ‘./app.component.html’, styleUrls: [‘./app.component.css’] }) export class AppComponent { title = ‘app works!’; }

La composición de un componente es la siguiente: El gran libro de Angular

57



Import: permite importar otros componentes a utilizarse dentro del componente que se está deniendo. Como mínimo, importamos Component de @angular/core.



Decorador: función de tipo decorador que posee un objeto con los metadatos que indican a Angular cómo se crea, compila y ejecuta el componente. Export class: exporta la clase asociada al componente para hacerla visible a otros componentes, de forma que puedan usar sus propiedades y métodos dependiendo a su vez de la visibilidad establecida a los mismos. Hace las veces de controlador en la clásica arquitectura MVC (Modelo-VistaControlador).



Los campos de metadata pueden ser los siguientes: Campo

Comentario

Selector

Nombre que se utiliza para hacer referencia a nuestro componente (p. ej., <mi-aplicacion>)

Template

Contenido HTML de nuestro componente.

TemplateURl

Cuando el contenido es voluminoso, usamos un chero externo para almacenar el template.

StyleUrls

Array que contiene las hojas de estilo que se van a utilizar.

Directives

Enumeración de las directivas que se van a emplear en el componente.

Providers

Enumeración de los providers que se van a utilizar.

En los siguientes ejercicios detallaremos los diferentes campos de tipo template y veremos cuándo es mejor usar un tipo u otro según cada caso. En el siguiente ejercicio, además de crear un proyecto y ver cómo crea el componente por defecto, crearemos otro componente adicional para ver cómo se hace con Angular CLI y cómo podemos utilizarlo fácilmente en nuestra aplicación. 1. En primer lugar, nos ubicaremos en ej100_angular y crearemos un proyecto denominado cmpCrea mediante ng new.

58

El gran libro de Angular

2. Seguidamente, renombraremos el proyecto para que haga referencia a nuestro número de ejercicio. Para ello, estando ubicados en el directorio Ej100_angular, simplemente escribiremos lo siguiente: C:\Ej100_angular>rename cmpCrea 015_cmpCrea 3. Ahora, abrimos nuestro proyecto con nuestro editor (en nuestro caso, usamos Atom) y observamos cómo ha quedado nuestro componente por defecto.

4. A continuación, nos ubicaremos de nuevo en nuestro directorio 015_ cmpCrea y crearemos nuestro nuevo componente compo1 tecleando lo siguiente (ng generate component compo1 o de forma abreviada): ng g c compo1 5. Observaremos el resultado de la creación en la ventana de CMD y también la estructura que ha creado en el proyecto. Seguidamente, modicamos app.component.html para añadir el tag y arrancamos nuestra app para ver cómo aparece en el navegador. Para ello, en la ventana de CMD teclearemos: C:\Ej100_angular\015_cmpCrea>ng serve

El gran libro de Angular

59

6. En el navegador, veremos cómo nuestra aplicación, además de mostrar el contenido de app.component.html (app Works!), muestra también el contenido por defecto de compo1.component.html (compo1 works!).

Vamos a hacer una pequeña modicación en nuestro componente para darle un poco de funcionalidad y, para ello, modicaremos el chero compo1. component.html para que tenga el siguiente contenido:



compo1 works!




{{ texto }} s4j3a



7. Observamos que simplemente hemos incluido un botón al que le hemos asociado un evento (click), el cual invocará a la función saludar() cuando pulsemos sobre el mismo. Estos conceptos se explicarán con más detalle en ejercicios posteriores. Modicaremos también al archivo compo1.component.ts para que la clase que se ha creado por defecto Compo1Component tenga lo siguiente: export class Compo1Component { texto: string; saludar() { this.texto = “Hola Mundo en compo1”; }

60

El gran libro de Angular

}

8. Vemos que en la clase simplemente se ha añadido la variable texto de tipo string y una función llamada saludar() que se invocará cuando pulsemos el botón que hemos añadido en nuestra vista. Mientras que la aplicación esté en marcha, cada modicación que realicemos se actualizará sobre la marcha en el propio navegador así que, en este punto, deberíamos ver nuestro botón Saludar.

9. Si pulsamos sobre el mismo, observaremos cómo nos saluda.

El gran libro de Angular

61

016

Componentes: Template inline

El Template es la parte del componente que permite diseñar la vista utilizando HTML y otros elementos como por ejemplo las directivas que veremos en ejercicios posteriores. Dicho template puede ser denido dentro del propio componente mediante el campo template situado dentro de la metadata del componente o bien, en el campo templateUrl mediante el cual deniríamos un archivo externo al que se haríamos referencia mediante su URL.

Importante Utilice este método cuando el HTML a denir sea realmente pequeño. En general, es mejor usar templateUrl para tener mejor organizado cada bloque de código.

En el siguiente ejercicio, crearemos un componente al que deniremos su template inline usando la opción --inline-template. 1. En primer lugar, nos ubicaremos en ej100_angular y crearemos un proyecto denominado cmpInline mediante ng new.

2. Seguidamente, renombraremos el proyecto para que haga referencia a nuestro número de ejercicio. Para ello, estando ubicados en el directorio Ej100_angular, simplemente escribiremos lo siguiente: C:\Ej100_angular>rename cmpInline 016_cmpInline

Ahora, abrimos nuestro proyecto con nuestro editor (en nuestro caso usamos Atom) y observamos como ha quedado nuestro componente (por defecto) app/app.component. 62

El gran libro de Angular

3. A continuación, nos ubicaremos de nuevo en nuestro directorio 016_ cmpInline y crearemos nuestro nuevo componente compo1 tecleando lo siguiente (ng generate component compo1 --inline-template o de forma abreviada): C:\Ej100_angular\016_cmpInline>ng g c compo1 --inline-template

Observaremos el resultado de la creación en la ventana de CMD y también, la estructura que ha creado en el proyecto. En ambas observaciones, podemos comprobar que el archivo compo1. component.html no se ha creado. Sin embargo, si abrimos nuestro archivo compo1. component.ts, observaremos que el contenido HTML se ha descrito en el campo template dentro de la metadata entre 2 acentos de tipo ‘grave’( , el que se halla en el corchete izquierdo):

El gran libro de Angular

63

@Component({ selector: ‘app-compo1’, template: `

compo1 Works!

`, styleUrls: [‘./compo1.component.css’] })

Seguidamente, modicamos app.component.html para añadir los tags y así mostrar nuestro compo1 y también, arrancamos nuestra app para ver cómo aparece en el navegador.

Para ello, en la ventana de CMD teclearemos: C:\Ej100_angular\016_cmpInline>ng serve

Si abrimos nuestro navegador y tecleamos http://localhost:4200/, veremos cómo se muestra nuestra aplicación, mostrando el contenido de app.component.html (app Works!) y también, el contenido HTML creado por defecto en nuestro compo1.component.ts (compo1 works!). 4. Igual que hicimos en el ejercicio anterior, añadimos un poco de funcionalidad modicando el HTML de compi1 con el siguiente contenido:

64

El gran libro de Angular

compo1 works!


{{ texto }} s4j3a



Modicaremos también al archivo compo1.component.ts para que la clase que se ha creado por defecto Compo1Component tenga lo siguiente: export class Compo1Component { texto: string; saludar() { this.texto = “Hola Mundo en compo1”;

}

}

Si pulsamos sobre el botón Saludar, observaremos cómo nos saluda.

El gran libro de Angular

65

017

Componentes: Styles inline

De forma similar a la descrita en el ejercicio anterior, la parte relacionada con CSS (lenguaje usado para denir la presentación de los documentos HTML o XML) también puede denirse dentro del propio componente usando el campo style de los metadatos, o bien mediante el empleo de una referencia a un chero con dicha denición si usamos el campo styleUrls (el cual puede ser una colección, ya que es de tipo array). En el siguiente ejercicio, añadiremos un componente al proyecto que creamos en el ejercicio anterior (016_ cmpInline) al que deniremos su style mediante la opción --inline-style.

Importante Utilice este método cuando el CSS que se desee denir sea realmente pequeño y no quiera denirlo en un archivo especíco asociado al componente. En general, es mejor usar styleUrls para tener mejor organizado cada bloque de código.

1. En primer lugar, nos ubicaremos en ej100_ angular\016_cmpInline y crearemos un nuevo componente denominado compo2 tecleando lo siguiente (ng generate component compo2 ----inline-style o de forma abreviada): C:\Ej100_angular\016_cmpInline>ng g c compo2 --inline-style

Observaremos el resultado de la creación en la ventana de CMD y también la estructura que ha creado en el proyecto. En ambos casos, podemos comprobar que no se ha creado el archivo compo2.component.css. Sin embargo, si abrimos nuestro archivo compo2.component.ts, veremos que ha creado un campo vacío (styles) dentro de metadata, en el cual podremos denir nuestro contenido CSS entre dos acentos de tipo grave ( `, el que se halla en el corchete izquierdo): 66

El gran libro de Angular

@Component({ selector: ‘app-compo2’, templateUrl: ‘./compo2.component.html’, styles: [] }) Seguidamente, modicamos app.component.html para añadir los tags y así mostrar nuestro compo2, y también arrancamos nuestra app para ver cómo aparece en el navegador.

C:\Ej100_angular\016_cmpInline>ng serve 2. Si abrimos nuestro navegador y tecleamos http://localhost:4200/, veremos cómo se muestra nuestra aplicación, mostrando el contenido de app. component.html (app Works!), el contenido del compo1 añadido en el ejercicio anterior (compo1 works! y su botón Saludar) y también el contenido HTML creado por defecto en nuestro compo2.component. html (compo2 works!).

3. Ahora, vamos a hacer una pequeña modicación en el CSS de compo2 para denir algunas características de presentación. Por ejemplo, haremos que El gran libro de Angular

67

los tags de tipo

muestren un tamaño de letra grande y que se aplique un fondo amarillo. También haremos que el texto comprendido entre los tags

se muestre en azul. Así pues, los metadatos de nuestro compo2 quedarán de la siguiente manera: @Component({ selector: ‘app-compo2’, templateUrl: ‘./compo2.component.html’, styles: [` p { font-size: xx-large ; background-color: yellow; } h2 { color: blue; } `] }) Seguidamente, añadimos un pequeño texto en el archivo compo2.component.html para poder comprobar cómo se visualizan los tags 5r2v5r

. Para ello, modicaremos dicho archivo para que quede de la siguiente manera: zk4d

compo2 works!

Texto en compo2 1q6970

4. Por último, si observamos nuestro navegador, veremos que se muestra el contenido de los 3 componentes (app, compo1 y compo2) y, concretamente, en nuestro último componente apreciaremos las características de presentación denidas inline.

68

El gran libro de Angular

018

Componentes: Propiedades

En un componente, podemos denir propiedades que utilizaremos para mostrar información en las vistas o para condicionar el aspecto de las mismas. Para indicar al DOM que una de sus propiedades está ligada a una propiedad de nuestro componente, usaremos los corchetes [ ], lo que denominaremos binding de propiedades (property binding). En posteriores ejercicios se abordará el DataBinding con más profundidad. Podemos también hacer un binding con las clases CSS para condicionar un estilo al valor de una propiedad. En el siguiente ejercicio, mostraremos unos cuantos ejemplos de cómo ligar algunas propiedades del DOM a propiedades de nuestro componente permitiendo así la visualización o no de un bloque, habilitar o deshabilitar un botón, denir un link a partir de un valor o de aplicar una clase CSS dependiendo del valor de una propiedad. 1. En primer lugar, nos ubicaremos en ej100_angular y crearemos el proyecto cmpProp mediante el comando ng new: C:\Ej100_angular>ng new cmpProp

Seguidamente, renombraremos el proyecto para que haga referencia a nuestro número de ejercicio. Para ello, ubicados en el directorio Ej100_angular, escribiremos lo siguiente: C:\Ej100_angular>rename cmpProp 018_cmpProp

A continuación, abrimos nuestro proyecto con nuestro editor (en nuestro caso, usamos Atom) y modicamos el archivo styles.css añadiendo una denición para las clases fondo (para div), td (para celdas de la tabla que incluiremos) y tamB para el tamaño de los botones:

El gran libro de Angular

69

.fondo { background: yellow; } td { text-align: center; vertical-align: middle; } .tamB { height:60px; width:200px }

Seguidamente, modicaremos nuestro archivo app/app.component.ts para que la clase AppComponent quede de la siguiente manera: export class AppComponent { title = ‘app works!’; ponFondo = true; mostrar = true; habilitar = false; referencia = “http://www.google.com”; }

A continuación, modicaremos el chero app.component.html para que tenga el siguiente contenido:

{{title}} 49413a







70 El gran libro de Angular
Fondo

Hola
{{ referencia }}

Se ve 1f2v4s



Observe que hemos añadido la siguiente referencia para poder utilizar Bootstrap y, de esta forma, añadir clases y funcionalidades a la aplicación:

Por último, ejecutamos la aplicación y vemos cómo se muestra en el navegador. Para ello, nos ubicamos en nuestro el directorio de la aplicación y tecleamos ng serve: C:\Ej100_angular>cd 018_cmpProp C:\Ej100_angular\018_cmpProp>ng serve

El gran libro de Angular

71

Una vez arrancada la aplicación, podemos marcar y desmarcar el check Fondo para ver cómo se aplica el fondo según tengamos marcado el check o no, podemos hacer clic sobre el link que en el componente denimos como http://www.google.com y veremos cómo se abre una pestaña con dicho URL, podemos pulsar sobre el botón Mostrar para exponer o no un determinado bloque o sobre el botón Deshabilitar para habilitar o no el botón con la etiqueta Prueba.

72

El gran libro de Angular

Importante Podemos ligar propiedades de la vista con las de nuestro componente mediante el empleo de property binding.

019

Componentes: Test Unitarios

En general, los test son una parte muy importante del deImportante sarrollo, ya que son los que han de garantizar el buen funcionamiento de nuestras aplicaciones y, por tanto, evitar Testee sus aplicaciones las posibles incidencias que pudieran aparecer una vez que para garantizar la el software esté en producción. Existen diversos tipos de calidad de las mismas y test, pero los desarrolladores, en principio, deberían apordemostrar un nivel de tar sus test unitarios como parte de la documentación de calidad a sus clientes sus desarrollos, demostrando el buen funcionamiento de documentando los mismos. Es tal la importancia que se otorga a los test, los resultados. que existe una metodología de desarrollo denominada TDD (test-driven development) o desarrollo orientado o dirigido por pruebas, que consiste en desarrollar inicialmente los test que han de superar los desarrollos y, a continuación, escribir el código que supere dichos test. Angular nos permite realizar test fácilmente ya que, por defecto, utiliza Jasmine (framework que permite probar código JavaScript) y Karma (“test runner” que permite automatizar algunas tareas de los frames de test). Es decir, sin congurar nada especialmente ya podríamos ejecutar un test justo después de crear un proyecto simplemente ejecutando npm test o ng test. La descripción de los test se apoya en cheros denominados spec, que contienen un describe de las pruebas que queremos implementar y un expect() por cada una de las operaciones y resultados esperados de dichas pruebas. Incluye una API que permite realizar multitud de comparaciones (toEqual, toBe, toContain, etc.) y que puede consultar en https://www. npmjs.com/package/jasmine-expect. En el siguiente ejercicio, elaboraremos un proyecto en el que incluiremos una clase para realizar una serie de operaciones matemáticas simples (sumar, restar, multiplicar y dividir) y a la que someteremos a un test para vericar qué parte de la misma está probada, falta por probar o puede contener un posible error. A pesar de que el tema de los test es amplio, consideramos que con este ejercicio podemos realizar una introducción suciente a este apasionante apartado de la programación. 1. En primer lugar, nos ubicaremos en ej100_ angular y crearemos el proyecto cmpTest mediante el comando ng new: C:\Ej100_angular>ng new cmpTest

El gran libro de Angular

73

Seguidamente, renombraremos el proyecto para que haga referencia a nuestro número de ejercicio. Para ello, estando ubicados en el directorio Ej100_ angular, escribiremos lo siguiente: C:\Ej100_angular>rename cmpTest 019_cmpTest

A continuación, crearemos la clase operaciones usando Angular CLI. Para ello, nos ubicaremos en el directorio de la nueva aplicación y teclearemos lo siguiente: C:\Ej100_angular>cd 019_cmpTest C:\Ej100_angular\019_cmpTest>ng generate class operaciones

Ahora, abrimos nuestra aplicación con el editor que usemos habitualmente (p. ej., Atom) y abrimos la nueva clase operaciones para denir las operaciones que queremos implementar. 2. Seguidamente modificaremos la clase AppComponent del chero app.component.ts para importar la clase Operaciones y para que contenga la función ngOnInit() con una muestra de ejecución de las operaciones denidas en la clase anterior. 3. Vamos a modicar el chero app.component. html para que contenga simplemente el título de la aplicación y algunos resultados tras el uso de nuestra clase.

4. Guardamos todo y arrancamos la aplicación con ng serve ubicándonos en C:\Ej100_ angular\019_cmpTest. 5. A continuación, borraremos el chero app.component.spec que se generó por defecto al crear la aplicación y, dentro de la carpeta src/app, crearemos el chero operaciones.spec.ts donde deniremos nuestros test con la estructura describre-it-expect.

74

El gran libro de Angular

6. Seguidamente, vamos a abrir otra sesión de CMD y, desde C:\Ej100_ angular\019_cmpTest, ejecutaremos ng test para ejecutar todos los archivos de tipo spec que tengamos denidos. En este punto, observaremos que ya nos indica que se han ejecutado dos pruebas con éxito (Executed 2 of 2 SUCCESS) y que, al mismo tiempo, se ha abierto una sesión de Chrome (navegador por defecto en la conguración que puede cambiarse) con el resultado de las pruebas que se han lanzado. En esta pantalla, vemos los textos que hemos incluido en describe y también que, de los dos resultados esperados, ha habido 0 fallos (2 specs, 0 failures).

7. Ahora, detenemos ng test pulsando CTRL+C y contestando S a la pregunta ¿Desea terminar el trabajo por lotes (S/N)? Una vez detenido, volveremos a lanzar el test con la opción –code-coverage: C:\Ej100_angular>ng test –code-coverage Aparentemente, el resultado es el mismo que hemos comentado anteriormente, pero si observamos la carpeta del proyecto, veremos que se ha creado dentro de otra carpeta denominada coverage, donde se almacenan los elementos que nos permitirán consultar qué parte del código se ha cubierto. Si pulsamos sobre el chero index.html, se muestra una página en la que puede analizarse cuál es el porcentaje de la aplicación que tenemos cubierto.

El gran libro de Angular

75

8. Si pulsamos sobre src/app para analizar qué parte nos falta, aparecerá otra pantalla que mostrará la clase operaciones que está incompleta respecto de las pruebas y, de nuevo, si pulsamos sobre operaciones, veremos cómo nos destaca el código pendiente de cubrir (multiplicar y dividir).

9. Vamos a completar los test que nos faltan añadiendo al chero operaciones.spec.ts lo siguiente justo después del describe que tenemos para sumar y restar. 10. Si relanzamos de nuevo el test con la opción – code-coverage, veremos que ahora aparecen dos nuevos test y si refrescamos la página index. html, observaremos que ahora ya tenemos el 100% de nuestra clase cubierto.

11. Para acabar, vamos a provocar un error para mostrar cómo se avisa el fallo de un test. Provoquemos el absurdo error de indicar que al sumar 3+5 el resultado es 9: expect(operaciones.sumar(3,5)) .toEqual(9) Al relanzar de nuevo el test (ng test) veríamos cómo aparece un fallo (1 failure) indicando dónde se ha encontrado (Test para operaciones Test para sumar y restar Suma 2 numeros) y cuál era el valor esperado (Expected 8 to equal 9). 76

El gran libro de Angular

020

Decoradores

Un decorador dene qué partes posee un elemento (componente, directiva, etc.) y permite extender la funcionalidad de una función empleando otra función. Mediante los decoradores, los componentes quedan registrados y pueden utilizarse en otras partes de la aplicación gracias a la información añadida. En denitiva, el decorador es una implementación del patrón de diseño decorator, el cual permite añadir funcionalidad a un objeto dinámicamente evitando tener que crear un conjunto de clases que hereden de la inicial simplemente para añadir funcionalidad adicional. Existen cuatro tipos principales de decoradores: • • • •

Importante La inmensa mayoría de los decoradores de uso frecuente nos los encontramos tras la creación de componentes, directivas, pipes, etc., que creamos con Angular CLI.

De clase (p.e. @Component and @NgModule). De propiedades (en las clases, p. ej., @Input and @Output). De métodos (p.e. @HostListener). De parámetros (en el constructor, p. ej., @Inject).

Los nombres de los decoradores empiezan con el símbolo @ seguido de un nombre que indica el elemento a decorar. Un ejemplo típico es el decorador @Component, el cual se utiliza para decorar componentes y puede emplearse siempre que importemos previamente la clase Component de @angular/core. Al crear un componente con Angular CLI, vimos cómo dicha sentencia se incluía de forma automática al inicio del archivo nombreCompo.component.ts. También hemos visto en ejercicios anteriores que, junto al decorador, se halla una metadata y que, en función del elemento a decorar, la misma varía. A continuación, mostramos una lista de decoradores de Angular y el módulo que se ha de importar desde @angular/ core mediante la sentencia: import { <MODULO> } from ‘@angular/core’; Por favor, consulte la documentación en https://angular.io/ para obtener más detalles.

El gran libro de Angular

77

Módulo a importar

Decorador

Uso

@Input

Permite que los componentes reciban datos de un componente padre.

Input

@Output

Permite que los componentes envíen datos a su padre.

Output

@Attribute

Recupera el valor de un atributo disponible en el elemento host de este componente.

Attribute

@Hostlistener

Escucha el evento emitido por el host e invoca el método decorado.

HostListener

@HostBinding

Actualiza el elemento host si un enlace de propiedad cambia.

HostBinding

@Component

Indica cómo procesar, instanciar y usar un componente en ejecución.

Component

@Directive

Añade comportamiento a los elementos del DOM.

Directive

@Host

DI busca una dependencia en cualquier inyector hasta llegar al host.

Host

@Inject

Especica una dependencia.

Inject

@Injectable

Indica a Angular que la clase puede ser usada con DI.

Injectable

@NgModule

Permite decorar módulos.

NgModule

@Optional

Parámetro que marca una dependencia como opcional. El inyector proporciona null si la dependencia no se encuentra.

Optional

@Pipe

Permite denir pipes.

Pipe

@Self

DI busca una dependencia propia, sin buscar hacia arriba en el árbol.

Self

@SkipSelf

DI busca dependencia en todo el árbol empezando por el padre.

SkipSelf

A continuación, realizaremos un ejercicio con @Attribute y @Hostlistener para mostrar el uso de decoradores.

78

El gran libro de Angular

1. En primer lugar, nos ubicaremos en ej100_ angular y crearemos el proyecto decora mediante el comando ng new: C:\Ej100_angular>ng new decora Seguidamente, renombraremos el proyecto para que haga referencia a nuestro número de ejercicio. Para ello, estando ubicados en el directorio Ej100_ angular, escribiremos lo siguiente: C:\Ej100_angular>rename decora 020_decora A continuación, desde el directorio 020_ decora crearemos un nuevo componente compo1 tecleando (ng generate component compo1 o de forma abreviada): C:\Ej100_angular\020_decora>ng g c compo1 Ahora, abrimos la aplicación con nuestro editor y añadimos en app.component.html lo siguiente:

De esta forma mostramos nuestro compo1 al arrancar la aplicación y también denimos un atributo que consumiremos desde nuestro componente mediante @Attribute. 2. Seguidamente, modicaremos el archivo compo1.component.html para añadir un par de variables que muestren las veces que hacemos clic o que pasamos el ratón sobre el componente y usar de esta forma el decorador @Hostlistener. El contenido será el siguiente:

compo1 works!


Clicks : {{ contaClick }}
MouseOver: {{ contaOver }}


El gran libro de Angular

79

En compo1.component.ts, modicaremos su contenido quedando de la siguiente manera: import { Component, Attribute, HostListener } from ‘@angular/ core’; @Component({ selector: ‘app-compo1’, templateUrl: ‘./compo1.component.html’, styleUrls: [‘./compo1.component.css’] }) export class Compo1Component { contaClick: number = 0; contaOver: number = 0; constructor( @Attribute(‘miAtributo’) atributo) {console. log(atributo); } @HostListener(‘click’, [‘$event’]) onHostClick(event: Event) { console.log(“click en app “ + event); this.contaClick += 1; } @HostListener(‘mouseover’, [‘$event’]) onMouseOver(event: Event) { console.log(“mouseover” + event); this.contaOver += 1; }

} Por último, arrancamos la aplicación ubicándonos en C:\Ej100_angular\020_decora y tecleando ng serve. En el navegador, moveremos el ratón sobre el componente y haremos algunos clics para ver cómo se actualiza el contador. Abrimos las herramientas de desarrollador (en Google Chrome pulse CTRL+MAYUS+I) y en la Console vemos cómo se muestran los mensajes que indican el Valor de muestra para atributo obtenido con @Attribute y cada evento ejecutado (MouseEvent) del ratón.

80

El gran libro de Angular

El gran libro de Angular

81

021

Comunicación entre componentes

La comunicación entre componentes puede realizarse de diversas maneras (servicios, observables, etc.), pero en este ejercicio, utilizaremos los decoradores @Input y @ Output mencionados brevemente en ejercicios anteriores. Habíamos comentado que, mediante @Input, podemos pasar datos desde un componente padre hacia un componente hijo. Con @Output, realizaremos lo contrario. Pasaremos datos desde un hijo hacia su padre.

Importante Utilice @Input y @Output para transferir datos de un componente “padre” a “hijo” y viceversa.

El siguiente ejercicio propone un proyecto muy simple en el que un componente padre se encarga de recoger dos valores que le pasa al hijo para realizar una operación sencilla (suma, resta, multiplicación y división) y, una vez obtenido el resultado, el mismo se devuelve al padre para que este se muestre en su vista. En primer lugar, desde ej100_angular, crearemos el proyecto comBC mediante ng new: C:\Ej100_angular>ng new comBC

Seguidamente, renombraremos el proyecto de la siguiente forma: C:\Ej100_angular>rename comBC 021_comBC A continuación, desde el directorio 021_comBC crearemos el componente compo1 tecleando: C:\Ej100_angular\021_comBC> ng g c compo1

82

El gran libro de Angular

Abrimos la aplicación con nuestro editor y dejamos en app.component. html el siguiente contenido:
Padre
Valor1
Valor2
Resultado {{ resultadoP }}


[valor1]=”valor1”

[valor2]=”valor2”

(envRes)=”captaResultado($event)” rel="nofollow">


En app.component.ts modicaremos la clase AppComponent para que tenga lo siguiente: export class AppComponent { valor1: string = ‘10’; valor2: string = ‘20’; resultadoP: number; captaResultado(event) { this.resultadoP = event; } }

Ahora, modicaremos compo1.component.html para añadir los botones con las operaciones: El gran libro de Angular

83

Hijo


Seguidamente, modicamos compo1.component.ts para que el import existente al inicio del chero contenga lo siguiente: import { Component, Input, Output, EventEmitter, AfterContentChecked } from ‘@angular/core’;

También modicaremos la clase Compo1Component con el siguiente contenido: export class Compo1Component { @Input() valor1: string; @Input() valor2: string; aux1: number; aux2: number; @Output() envRes: EventEmitter = new EventEmitter (); ngAfterContentChecked() { this.aux1 = parseFloat(this.valor1); this.aux2 = parseFloat(this.valor2); } suma()

{ this.envRes.emit(this.aux1 + this.aux2); }

resta()

{ this.envRes.emit(this.aux1 - this.aux2); }

multiplica() { this.envRes.emit(this.aux1 * this.aux2); } divide()

{ this.envRes.emit(this.aux1 / this.aux2); }

}

84

El gran libro de Angular

Por último, modicaremos el archivo styles.css con lo siguiente: div{ width:250px; padding: 20px; display: block; text-align: center; } .padre { background: #abe4b8; } .hijo

{ background: #5af0f0; }

.tamB

{ height:53px; width:53px; font-size: 20px; }

Arrancamos la aplicación tecleando ng serve desde C:\Ej100_angular\021_comBC y vemos la aplicación en el navegador. Probaremos las distintas operaciones (suma, resta, multiplicación y división) para comprobar cómo el resultado llega al padre a través del evento que se lanza desde el hijo y que se captura desde el padre.

El gran libro de Angular

85

86

El gran libro de Angular

022

Componentes: Ciclo de vida (Lifecycle hooks)

Las directivas y componentes poseen un ciclo de vida de tal manera que se crean, se actualizan y nalmente se destruyen. Angular ofrece los lifecycle hooks (o “ganchos” del ciclo de vida) para que los desarrolladores puedan aprovecharlos por mediación de interfaces cuyo nombre es idéntico al evento producido, pero anteponiéndole el prejo ng. Las directivas poseen un ciclo más corto. Los lifecycle hooks son los siguientes:

Importante Podemos usar algunos métodos para aprovecharnos de las acciones que se realizan durante el ciclo de vida de un componente como, por ejemplo, inicializar variables o destruir recursos antes de que el componente sea destruido.

• ngOnChanges: cuando se detectan cambios en las propiedades de entrada. El método recibe un objeto SimpleChanges de los valores de propiedad actuales y anteriores. • ngOnInit: tras la primera ejecución de ngOnChanges. Se llama solo una vez e inicializa el componente o directiva. Usamos este método para realizar inicializaciones justo después de la construcción del componente. Es un buen lugar para cargar datos. • ngDoCheck: se usa para actuar sobre los cambios que Angular no captura y que pueden tener cierto interés más allá de un simple cambio de estado. • ngAfterContentInit: después de inicializar el contenido del componente. Solo existe en los componentes. • ngAfterContentChecked: tras cada comprobación del contenido del componente. Solo existe en los componentes. Comprueba el contenido visualizado en el componente. • ngAfterViewInit: después de que las vistas del componente se inicialicen y después de ngAfterContentChecked. •ngAfterViewChecked: después de cada comprobación de la vista de un componente. Se llama después de ngAfterViewInit y de cada ngAfterContentChecked. • ngOnDestroy: antes de destruir el componente. Usamos este método para realizar la limpieza de recursos que El gran libro de Angular

87

Angular no realiza automáticamente y es un buen lugar para avisar a otros componentes de que el componente en curso se va a destruir. En el siguiente ejercicio realizaremos una pequeña aplicación en la que generaremos una traza de forma que podamos monitorizar cuál es la secuencia en la que sucede cada uno de estos momentos del ciclo de vida de un componente mediante la consola del navegador. 1. En primer lugar, nos ubicaremos en ej100_angular y crearemos el proyecto cmpLH mediante el comando ng new. Seguidamente, renombraremos el proyecto para que haga referencia a nuestro número de ejercicio. Para ello, ubicados en el directorio Ej100_angular, usaremos el comando rename. A continuación, nos ubicaremos en nuestro directorio 022_cmpLH y crearemos un nuevo componente (compo1) con el comando ng. C:\Ej100_angular>ng new cmpLH C:\Ej100_angular>rename cmpLH 022_cmpLH C:\Ej100_angular>cd 022_cmpLH C:\Ej100_angular\022_cmpLH>ng g c compo1

Una vez creado el componente, abriremos la aplicación con nuestro editor y modicaremos el archivo app.component.html para incluir nuestro componente compo1:

88

El gran libro de Angular

{{title}} 49413a



En app.component




Observemos que dentro de las etiquetas , hemos indicado que queremos pasar a compo1, el valor de la variable salidaPadre de app.component.ts (que deniremos a continuación) dentro de la variable entradaHijo (que también deniremos en compo1). 2. Modicamos app.component.ts para que la clase AppComponent quede de la siguiente manera: export class AppComponent { title = ‘app works!’; salidaPadre: string = “”; }

Modicamos el archivo compo1/compo1.component.html para que tenga el siguiente contenido:

compo1 works!


En compo 1

Hola {{ entradaHijo }}



En la clase de compo1 modicaremos el import existente para que tenga lo siguiente: import { Component, OnInit, SimpleChanges, Input, OnChanges, ViewChild } from ‘@angular/core’;

3. En la clase Compo1Component incluimos un método por cada momento del ciclo de vida:

El gran libro de Angular

89

export class Compo1Component implements OnInit { @Input() entradaHijo: string = “”; contador: number = 0; constructor() { } ngOnInit() { this.mostrar(“pasa por ngOnInit”); } ngOnChanges(cambios: SimpleChanges) { for (let propiedad in cambios) { let cambio = cambios[propiedad]; let actual = JSON.stringify(cambio.currentValue); let anterior = JSON.stringify(cambio.previousValue); this.mostrar(“Pasa por ngOnChanges. Propiedad (“ + propiedad + “) valor actual (“ + actual + “) valor anterior (“ + anterior + “)”); } } ngDoCheck() { this.mostrar(“pasa por ngDoCheck”); } ngAfterContentInit() { this.mostrar(“pasa por ngAfterContentInit”); } ngAfterContentChecked() { this.mostrar(“pasa por ngAfterContentChecked”); } ngAfterViewInit() { this.mostrar(“pasa por ngAfterViewInit”); } ngAfterViewChecked() { this.mostrar(“pasa por ngAfterViewChecked”); } public mostrar(texto: string) { this.contador += 1; console.log(this.contador + “ - “ + texto); } }

Ahora, ubicados en el directorio 022_cmpLH, ejecutaremos ng serve y observaremos cómo se muestra nuestra aplicación en el navegador.

90

El gran libro de Angular

4. Una vez en el navegador, si estamos usando Google Chrome, mostraremos la Console acudiendo a Más herramientas -> Herramientas para desarrolladores.

5. De esta forma, podremos ver los displays de texto que se generan cada vez que ejecutamos la aplicación y cada vez que introducimos algún carácter en las cajas de texto de las vistas.

El gran libro de Angular

91

023

Directivas: Denición

Las directivas permiten añadir a HTML un comportamiento dinámico mediante una etiqueta o un selector. Dependiendo del tipo de directiva, podemos cambiar la apariencia o comportamiento de un elemento o incluso añadir o eliminar elementos del DOM (document object model o modelo de objetos del documento).

Importante Utilice las directivas para cambiar el aspecto de sus elementos y modicar la estructura del DOM dinámicamente.

Básicamente, existen dos tipos de directivas: Directivas estructurales: alteran la estructura del DOM añadiendo, sustituyendo o eliminando elementos. Empiezan por asterisco (*). • ngFor: permite iterar sobre una lista de elementos y realizar diversas acciones en un HTML como, por ejemplo, fabricar listas. • ngIf: en base a una evaluación, crea o elimina elementos en el DOM. • ngSwitch: gestiona conjuntos de tags eliminando los que no cumplan una condición. • Directivas de atributo: modican la apariencia de un elemento o modican su comportamiento. • ngClass: permite añadir o eliminar dinámicamente una o varias clases CSS en un elemento. • ngModel: habilita un mecanismo de binding bi-direccional. • ngStyle: permite asignar varios estilos inline a un elemento. También podemos considerar que un componente es un tipo de directiva concreto al que se le ha dado un decorador propio por tratarse de un caso especial. •

En el siguiente ejercicio se muestra cómo poder aplicar dos clases de forma condicional con ngClass. 1. En primer lugar, nos ubicaremos en ej100_angular y crearemos un proyecto denominado dirNgClass.

92

El gran libro de Angular

2. Seguidamente, renombraremos el proyecto para que haga referencia a nuestro número de ejercicio. Para ello, ubicados en el directorio Ej100_ angular, simplemente escribiremos lo siguiente: C:\Ej100_angular>rename dirNgClass 023_dirNgClass A continuación, podemos ubicarnos en nuestro nuevo directorio y arrancar la aplicación para verla en nuestro navegador. Para ello, teclearemos lo siguiente: C:\Ej100_angular>cd 023_dirNgClass C:\Ej100_angular\023_dirNgClass>ng serve

Ahora, abrimos nuestro proyecto con nuestro editor (en nuestro caso, usamos Atom) y modicamos el archivo styles.css añadiendo una denición para las clases fa (fondo amarillo) y lg (letra grande): .fa { background-color: rgb(255,246,51); } .lg { font-size: 200%; } Seguidamente, modicaremos nuestro archivo app.component.ts para que la clase AppComponent quede de la siguiente manera:

El gran libro de Angular

93

export class AppComponent { title = ‘023 dirNgClass’; fondoAmarillo=false; letraGrande=false; checkFondo(){ this.fondoAmarillo=!this.fondoAmarillo; } checkLetra(){ this.letraGrande=!this.letraGrande; } asignaClases(){ let classes = { fa: this.fondoAmarillo, lg: this.letraGrande }; return classes; } } 3. Por último, modicaremos el chero app.component.html para que tenga el siguiente contenido:

{{title}} 49413a

Fondo. (fondoAmarillo = {{fondoAmarillo}})
Tam.letra. (letraGrande = {{letraGrande}})
Este texto variará según el resultado del método.
Si fondoAmarillo=true -> el fondo será amarillo.
Si letraGrande=true -> las letras serán grandes.

94

El gran libro de Angular

4. En el navegador, observaremos que nuestra aplicación muestra un texto con dos checkboxs que permiten cambiar el fondo de nuestro div y aumentar el tamaño de la letra según si los marcamos o no, o hacer ambas cosas. Pruebe a marcar y desmarcar para comprobar el efecto.

El gran libro de Angular

95

024

Directivas: ngIf

Importante Utilizar *ngIf permite optimizar recursos al reducir el DOM y, con ello, facilitar la transferencia de recursos por la red.

Tal y como habíamos comentado en el ejercicio anterior, *ngIf permite añadir o eliminar un elemento al DOM si se cumple una determinada condición. A diferencia de la propiedad visibility de CSS donde se puede ocultar un elemento, ngIf lo elimina físicamente si la condición no se cumple, de forma que no consume recursos.

En el siguiente ejercicio, mostramos unos elementos div basándonos en *ngIf y en el valor asociado a unas variables de tipo Boolean. Dichos div se hallan anidados en una sencilla jerarquía que hemos llamado grupos, los cuales contienen subgrupos. 1. En primer lugar, nos ubicaremos en ej100_angular y crearemos el proyecto dirNgIf mediante el comando ng new: C:\Ej100_angular>ng new dirNgIf

Seguidamente, renombraremos el proyecto para que haga referencia a nuestro número de ejercicio. Para ello, estando ubicados en el directorio Ej100_ angular, escribiremos lo siguiente: C:\Ej100_angular>rename dirNgIf 024_dirNgIf

A continuación, nos ubicaremos en 024_dirNgIf y arrancaremos la aplicación para comprobar cómo funciona en nuestro navegador. Para ello, teclearemos lo siguiente:

96

El gran libro de Angular

C:\Ej100_angular>cd 024_dirNgIf C:\Ej100_angular\024_dirNgIf >ng serve

Ahora, abrimos nuestro proyecto con nuestro editor (en nuestro caso, usamos Atom) y modicamos el archivo styles.css añadiendo una denición para las clases uno (para div de tipo grupos), dos (para subgrupos) y tamB para el tamaño de los botones: .uno{ border: 3px solid #F00; background-color: lightblue;} .dos{ border: medium double #369; background-color: yellow; } .tamB{ height:40px; width:300px; }

Seguidamente, modicaremos nuestro archivo app.component.ts para que la clase AppComponent quede de la siguiente manera: export class AppComponent { title = ‘024 dirNgIf’; grupo1=false; grupo2=false; subgrupo11=false; subgrupo12=false; subgrupo21=false; subgrupo22=false; }

A continuación, modicaremos el chero app.component.html para que tenga el siguiente contenido:

El gran libro de Angular

97

{{title}} 49413a


Grupo1.

Subgrupo11

Subgrupo12


Grupo2.

Subgrupo21

Subgrupo22


98

El gran libro de Angular

Observe que hemos añadido la siguiente referencia para poder utilizar Bootstrap y de esta forma, añadir clases y funcionalidades a la aplicación:

Por último, observaremos el aspecto de nuestra aplicación en el navegador. Si pulsamos sobre el botón del Grupo1 veremos cómo se despliega el div asociado. Si pulsamos sobre Subgrupo11 y Subgrupo12 aparecen los div de dichos subgrupos. Si pulsamos sobre todos los botones veremos todos los div asociados.

El gran libro de Angular

99

025

Directivas: ngFor

La directiva ngFor permite insertar bloques de código HTML de forma dinámica, basándose en una lista de elementos (en general, arrays). La sintaxis general es la siguiente:

donde tag es el elemento HTML que queremos crear según el número de iteraciones (p. ej., div, p, li, etc.) y elementos en la lista de elementos que iremos asignando uno a uno a elemento mediante let. Podemos averiguar el número del elemento que se está tratando si añadimos let i=index, tal y como se muestra a continuación:

Importante Utilice *ngFor para generar bloques HTML basándonos en el contenido de una lista de elementos.



En primer lugar, nos ubicaremos en ej100_angular y crearemos el proyecto dirNgFor.

1. Seguidamente, renombraremos el proyecto para que haga referencia a nuestro número de ejercicio. Para ello, ubicados en el directorio Ej100_ angular, escribiremos lo siguiente:

100

El gran libro de Angular

C:\Ej100_angular>rename dirNgFor 025_dirNgFor

A continuación, nos ubicaremos en 025_dirNgFor y arrancaremos la aplicación para comprobar cómo funciona en nuestro navegador. Para ello, teclearemos lo siguiente: C:\Ej100_angular>cd 025_dirNgFor C:\Ej100_angular\025_dirNgFor >ng serve

Ahora, abrimos nuestro proyecto con nuestro editor (en nuestro caso, usamos Atom) y modicamos el archivo app.component.ts para que la clase AppComponent quede de la siguiente manera: export class AppComponent { title = ‘025 dirNgFor’; public nombres = [ {nom:”uno”,edad:10}, {nom:”dos”,edad:20}, {nom:”tres”,edad:30} ]; }

Podemos observar que hemos creado un pequeño array denominado nombres con tres objetos compuestos únicamente por el campo nom y edad. 2. A continuación, modicaremos el chero app.component.html para que tenga el siguiente contenido:

El gran libro de Angular

101

{{title}} 49413a


  • {{i + 1}} -

    Nombre:

    {{ nombre.nom }}



    , edad: {{ nombre.edad}}



Observe que hemos añadido la siguiente referencia para poder utilizar Bootstrap y, de esta forma, añadir clases y funcionalidades a la aplicación:

Ahora, observaremos el aspecto de nuestra aplicación en el navegador. 3. Si lo desea, comente la primera línea del archivo app.component.html (la de
102

El gran libro de Angular

El gran libro de Angular

103

026

Directivas: ngSwitch

La directiva ngSwitch funciona como el clásico switch que podemos encontrar en multitud de lenguajes (p. ej., JavaScript). Es decir, evalúa una expresión y compara su resultado con una serie de valores añadiendo al DOM el bloque asociado en caso de coincidencia. Funciona con los siguientes elementos:

Importante Utilice *ngSwitch cuando necesite usar varios ngIf que usan la misma expresión y quiera mostrar un bloque en el caso de que no se cumpla ninguna comparación con los valores existentes.

Keywords

Comentarios

[ngSwitch]=”variable”

Expresión que se dene como un atributo y que evalúa el contenido de variable. Utiliza la propiedad binding. Como variable, también puede usarse una interpolación ({{ exp }} como veremos en ejercicios posteriores). Dene la comparación que se va a realizar. Si se cumple, se muestra el elemento HTML asociado (div, p, li, etc.).

*ngSwitchCase

*ngSwitchDefault

Dene el elemento por defecto que se va a mostrar cuando no hay ninguna coincidencia.

A continuación, mostramos una estructura simple: <elemento [ngSwitch]=”variable”> <elemento *ngSwitchCase=”’valor1’”>… <elemento *ngSwitchCase=”’valor2’”>… <elemento *ngSwitchDefault>…

También podríamos utilizar la siguiente sintaxis: <elemento ngSwitch=”{{ variable }}”>

104

El gran libro de Angular

En el siguiente ejercicio vamos a mostrar un bloque u otro según el valor que asignemos a una variable al pulsar alguno de los botones incluidos en nuestra página. 1. En primer lugar, nos ubicaremos en ej100_angular y crearemos el proyecto dirNgSwitch.

2. Seguidamente, renombraremos el proyecto para que haga referencia a nuestro número de ejercicio. Para ello, estando ubicados en el directorio Ej100_angular, escribiremos lo siguiente: C:\Ej100_angular>rename dirNgSwitch 026_dirNgSwitch

A continuación, nos ubicaremos en 026_dirNgSwitch y arrancaremos la aplicación para comprobar cómo funciona en nuestro navegador. Para ello, teclearemos lo siguiente: C:\Ej100_angular>cd 026_dirNgSwitch C:\Ej100_angular\026_dirNgSwitch>ng serve

Ahora, abrimos nuestro proyecto con nuestro editor (en nuestro caso, usamos Atom) y modicamos el título de la aplicación dentro del archivo app. component.ts para que la clase AppComponent quede de la siguiente manera: export class AppComponent { title = ‘026 dirNgSwitch’; }

Seguidamente, modicamos el archivo styles.css añadiendo una denición para los colores de fondo de un par de DIV (bg y bg2) dejando el siguiente contenido:

El gran libro de Angular

105

.bg { background-color: #F9E79F; } .bg2 { background-color: #D5F5E3; }

A continuación, modicaremos el chero app.component.html para que tenga el siguiente contenido:

{{title}} 49413a




Valor seleccionado:

Ha elegido la opcion: A
Ha elegido la opcion: B
Ha elegido la opcion: C
Sin selección


Boton pulsado : {{opcion}} 70683f


Observe que hemos incluido la siguiente referencia para poder utilizar Bootstrap y, de esta forma, añadir clases y funcionalidades a la aplicación:

106

El gran libro de Angular



Hemos querido poner tres botones de diferentes tamaños para ver algunas posibilidades de Bootstrap. 3. Ahora, observaremos el aspecto de nuestra aplicación en el navegador. Vemos que, hasta que no pulsemos ningún botón, se mostrará el texto Sin selección.

4. Pulse cualquier botón para ver que, al cambiar de valor la variable opcion, también cambia el texto de Valor seleccionado.

El gran libro de Angular

107

027

Directivas: ngModel

ngModel es un mecanismo que permite actualizar los valores de las variables usadas en el componente y en el archivo HTML de forma bidireccional. Este tema se ve con más detalle en los ejercicios dedicados al DATABINDING (One Way y Two Way). Antes de poder utilizar ngModel hemos de importar el FormsModule y añadirlo en la lista de módulos importados en app.module.ts, tal y como explicamos en el ejercicio posterior:

Importante Utilice *ngModel para actualizar de forma bidireccional el contenido de variables entre componentes y formularios o archivos HTML.

import { FormsModule } from ‘@angular/forms’; … imports: [ BrowserModule, FormsModule ],

El ejemplo más típico utiliza el elemento INPUT para mostrar su funcionamiento y su sintaxis general es la siguiente:

A la notación [()] también se le conoce como banana in a box por la forma gráca resultante al imaginar que los corchetes representan una caja y los paréntesis una banana. En el siguiente ejemplo, vamos a trabajar con dos elementos de tipo INPUT donde observaremos que, al escribir en cualquiera de ellos, se copiará el texto al otro convirtiendo a minúsculas todo el texto en uno de ellos y a mayúsculas en el otro. Al mismo tiempo, mostraremos mediante interpolación el contenido de ambos INPUT. Hemos incluido un *ngIF para que el texto resultante de la concatenación solo se muestre si hay algún carácter introducido en cualquier INPUT. 1. En primer lugar, nos ubicaremos en Ej100_angular y crearemos el proyecto dirNgModel utilizando ng new.

108

El gran libro de Angular

2. Seguidamente, renombraremos el proyecto para que haga referencia a nuestro número de ejercicio. Para ello, estando ubicados en el directorio Ej100_angular, escribiremos lo siguiente: C:\Ej100_angular>rename dirNgModel 027_dirNgModel

A continuación, nos ubicaremos en 027_dirNgModel y arrancaremos la aplicación para comprobar cómo funciona en nuestro navegador. Para ello, teclearemos lo siguiente: C:\Ej100_angular>cd 027_dirNgModel C:\Ej100_angular\027_dirNgModel>ng serve

Tal y como habíamos anticipado al principio, hemos de modicar también el archivo app.module.ts para que contenga las importaciones comentadas y, en denitiva, lo siguiente: import { BrowserModule } from ‘@angular/platform-browser’; import { NgModule } from ‘@angular/core’; import { FormsModule } from ‘@angular/forms’; import { AppComponent } from ‘./app.component’; @NgModule({ declarations: [ AppComponent ], imports: [ BrowserModule, FormsModule ], providers: [], bootstrap: [AppComponent], }) export class AppModule { }

Ahora, abrimos nuestro proyecto con nuestro editor (en nuestro caso, usamos Atom) y modicamos el archivo app.component.ts para que la clase AppComponent quede de la siguiente manera:

El gran libro de Angular

109

export class AppComponent { title

= ‘027 dirNgModel’;

nombre

= ‘’;

nombre2 = ‘’; cambiaNombre() { this.nombre=this.nombre.toLowerCase(); this.nombre2=this.nombre.toUpperCase(); } cambiaNombre2() { this.nombre2=this.nombre2.toUpperCase(); this.nombre=this.nombre2.toLowerCase(); } }

Seguidamente, modicamos el archivo styles.css añadiendo una denición para los colores de fondo de los div existentes (bg y bg2) dejando el siguiente contenido: .bg { background-color: #F9E79F; } .bg2 { background-color: #D5F5E3; }

A continuación, modicaremos el chero app.component.html para que tenga el siguiente contenido:

{{title}} 49413a






Hola {{ nombre }} / {{ nombre2 }} 6365s



110

El gran libro de Angular

Observemos cómo se ve ahora nuestra aplicación en el navegador.

3. Si introducimos el texto JuAnTo en cualquiera de las cajas de texto correspondientes a los INPUT, veremos cómo en la primera caja aparece todo el texto en minúsculas y en la segunda, en mayúsculas.

El gran libro de Angular

111

028

Directivas: ngStyle

ngStyle permite asignar varios estilos inline a un elemento con la denición de una serie de estilos o bien al asociar una función que devuelve uno o varios estilos en función de una serie de condiciones. La sintaxis general es: [ngStyle]=”{‘propiedad1’: variable, ‘propiedad2’: ‘valor2’}”

Por ejemplo: [ngStyle]=”{‘color’: color, ‘font-weight’: ‘bold’}”

Si asociamos una función usaríamos: [ngStyle]=”funcion()”

Por ejemplo: [ngStyle]=”deneEstilos()”

En el siguiente ejercicio, mostraremos un div en el que usamos ngStyle aplicando unos estilos más o menos jos que solo se apoyan en una variable para determinar el color del texto y, a continuación, mostraremos un div al que asociamos una función que evaluará varias condiciones y dará como resultado un conjunto de estilos que se aplicarán simultáneamente. Al igual que en el ejercicio anterior, tendremos que importar FormsModule para utilizar ngModel (como veremos a lo largo del ejercicio).

Importante Utilice *ngStyle cuando tenga que aplicar diferentes estilos en función de una serie de condiciones.

1. En primer lugar, nos ubicaremos en Ej100_angular y crearemos el proyecto dirNgStyle utilizando ng new.

112

El gran libro de Angular

2. Seguidamente, renombraremos el proyecto para que haga referencia a nuestro número de ejercicio. Para ello, ubicados en el directorio Ej100_ angular, escribiremos lo siguiente: C:\Ej100_angular>rename dirNgStyle 028_dirNgStyle

A continuación, nos situaremos en 028_dirNgStyle y arrancaremos la aplicación para comprobar cómo funciona en nuestro navegador. Para ello, teclearemos lo siguiente: C:\Ej100_angular>cd 028_dirNgStyle C:\Ej100_angular\028_dirNgStyle>ng serve

Ahora, abrimos nuestro proyecto con nuestro editor (en nuestro caso, usamos Atom) y, tal y como habíamos anticipado al principio, hemos de modicar el archivo src/app/app.module.ts para que contenga las importaciones comentadas y, en denitiva, lo siguiente: import … import { FormsModule } from ‘@angular/forms’; … imports: [ BrowserModule, FormsModule ], … }) export class AppModule { }

Seguidamente modicamos el archivo app.component.ts para que la clase AppComponent quede de la siguiente manera:

El gran libro de Angular

113

export class AppComponent { title

= ‘028 dirNgStyle’;

color = ‘blue’; hayLetraGrande:boolean

= false;

hayColorFondo:boolean

= false;

hayLetraColor:boolean

= false;

hayLetraItalica:boolean

= false;

deneEstilos(){ let styles= { ‘font-size’: this.hayLetraGrande ? ‘300%’ : ‘initial’, ‘background-color’: this.hayColorFondo ? ‘#58FA58’ : ‘#FFFFFF’, ‘color’: this.hayLetraColor ? ‘red’ : ‘black’, ‘font-style’: this.hayLetraItalica ? ‘italic’ : ‘normal’ }; return styles; } }

Seguidamente, modicamos el archivo styles.css al añadir una denición para cada uno de los div existentes (div1 y div2), dejando el siguiente contenido: .div1 { border-top: 10px solid blue; border-bottom: 5px solid red; height: 120px; width: 70%; background-color: #A9E2F3; } .div2 { border: 10px solid green; height: 100px; width: 70%; background-color: #58FA58; text-align: center; }

114

El gran libro de Angular

A continuación, modicaremos el chero app.component.html para que tenga el siguiente contenido:

{{title}} 49413a


Texto2

Tamaño
Fondo
Color
Italica

Texto


Observemos cómo se ve ahora nuestra aplicación en el navegador.

3. Si marcamos los checkbox (Tamaño, Fondo, Color, Italica) veremos cómo varían los estilos del bloque inferior.

El gran libro de Angular

115

116

El gran libro de Angular

029

Directivas: Mezcla

En el siguiente ejercicio realizaremos una aplicación en Importante la que se combinan las directivas mostradas en los ejercicios anteriores. Mostraremos una colección de númeUtilice las directivas ros y un par de checkbox para escoger la visualizasiempre que pueda para ción de números pares o impares, ambos o ninguno. simplicar su trabajo y En primer lugar, se muestra un botón mediante el cual dejar que sea Angular podemos usar *ngIf visualizando (o no) el div prinquien aplique la parte cipal con los checkbox y números. Para los checmecánica que sea posible para alterar kbox, usaremos ngClass para llamar a la función el DOM. clActividad() que aplicará una clase cambiando el color (activo o inactivo). A continuación, usaremos el *ngFor para crear un div por cada uno de los números existentes en un array de números denido en el componente. Luego, usaremos ngSwitch para determinar el valor a comparar en *ngSwitchCase. Dicho valor será el resto de dividir el índice de cada elemento dentro de la lista entre dos para saber si es par o impar. Según sea par o impar, se aplicará un color con ngStyle. Al igual que en los ejercicios anteriores, tenemos que importar el FormsModule y añadirlo en la lista de módulos importados en app.module.ts, tal y como explicaremos a lo largo del ejercicio. 1. En primer lugar, nos ubicaremos en Ej100_angular y crearemos el proyecto dirNgMezcla utilizando ng new.

2. Seguidamente, renombraremos el proyecto ubicándonos en Ej100_angular y escribiendo lo siguiente: C:\Ej100_angular>rename dirNgMezcla 029_dirNgMezcla

El gran libro de Angular

117

A continuación, nos situaremos en 029_dirNgMezcla y arrancaremos la aplicación para comprobar cómo funciona en nuestro navegador. Para ello, teclearemos lo siguiente: C:\Ej100_angular>cd 029_dirNgMezcla C:\Ej100_angular\029_dirNgMezcla>ng serve

Ahora, abrimos nuestro proyecto y modicamos el archivo src/app/app. module.ts para que contenga las importaciones comentadas y, en denitiva, lo siguiente: … import { FormsModule } from ‘@angular/forms’; … imports: [ BrowserModule, FormsModule ], …

Seguidamente modicamos app.component.ts para que la clase AppComponent quede así: export class AppComponent { title

= ‘029 dirNgMezcla’;

mostrar = false; numeros:number [] = [1,2,3,4,5,6]; pares:boolean = true; impares:boolean = true; colorPar = ‘blue’; colorImpar = ‘red’; clActividad(valor){ let classes = { activo: valor, inactivo: !valor }; return classes; } }

Seguidamente, modicamos styles.css añadiendo diversas deniciones para div, textos y el botón:

118

El gran libro de Angular

.divBg { border: 10px solid green; width: 70%; background-color: #F3F781; } .tamB { height:40px; width:50%; } .activo

{ color: blue; }

.inactivo{ color:red;

}

A continuación, modicaremos el chero app.component.html para que tenga el siguiente contenido:

{{title}} 49413a




<span [ngClass]=”clActividad(pares)”>pares
<span [ngClass]=”clActividad(impares)”>impares

<span [ngStyle]=”{‘color’: colorPar}”> {{i + 1}} - Numero:

{{ numero }}



<span [ngStyle]=”{‘color’: colorImpar}”> {{i + 1}} - Numero:

{{ numero }}





El gran libro de Angular

119

Observemos cómo se ve ahora nuestra aplicación en el navegador. Si pulsamos el botón Mostrar, se visualiza el div principal con los números. Si desmarcamos los impares, vemos que el texto se pone rojo y solo se visualizan los pares. Por último, si desmarcamos los pares, solo se visualizan los checkbox.

120

El gran libro de Angular

030

Pipes: Uso, parametrización y encadenamientos

Importante Los pipes nos permitirán realizar transformaciones de datos desde los mismos templates o documentos HTML.

Cuando las aplicaciones muestran datos a los s, raramente los muestran tal y como llegan desde los servicios u otras fuentes. Normalmente, lo que hacen es aplicar algún tipo de transformación antes de visualizarlos. Por ejemplo, una aplicación normalmente no mostraría una fecha como “Sun June 12 1977 00:00:00 GMT+0200 (Central European Summer Time)”, sino que lo haría como “June 12, 1977”.

Para realizar estas transformaciones tan comunes, Angular ofrece los pipes. Los pipes nos permitirán realizar las transformaciones desde los mismos templates o documentos html. Vamos a ver unos ejemplos: 1. Nos ubicaremos en ej100_angular, y crearemos el proyecto tecleando ng new pipeIntro. Seguidamente lo renombraremos para que haga referencia a nuestro número de ejercicio al ejecutar rename pipeIntro 030_ pipeIntro, y nalmente pondremos en marcha la aplicación tras ejecutar ng serve desde la carpeta 030_pipeIntro.

2. Ahora abriremos nuestro proyecto con nuestro editor (en nuestro caso, usamos Atom) y añadiremos el siguiente código en los siguientes archivos sobrescribiendo todo su contenido. src/app/app.component.ts

El gran libro de Angular

121

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

@Component({ selector: ‘app-root’, templateUrl: ‘./app.component.html’, styleUrls: [‘./app.component.css’] }) export class AppComponent { fecha1 = new Date(1988, 3, 15); //15 de Abril del 1988 } src/app/app.component.html

Fecha (sin pipe)

: {{ fecha1 }}



Fecha (DatePipe): {{ fecha1 | date }}



En el navegador veremos lo siguiente: Fecha (sin pipe) : Fri Apr 15 1988 00:00:00 GMT+0200 (Hora de verano romance) Fecha (DatePipe): Apr 15, 1988

Todos los pipes funcionan de igual manera: dentro de la expresión de interpolación (“{{…}}”), justo después de la propiedad del componente, se añade un operador de pipe ‘|’ y, a continuación, se añade el tipo de pipe a usar. Angular incorpora todo un conjunto de pipes para que puedan usarse desde cualquier template: DatePipe para formatear una fecha, UpperCasePipe para transformar texto a mayúscula, LowerCasePipe para transformar texto a minúscula, CurrencyPipe para formatear un número como moneda, PercentPipe para formatear un número como porcentaje, etc. Pero, además, también nos permite crear nuevos pipes personalizados. Por otra parte, un pipe puede aceptar parámetros. Estos se pasarán a la pipe a través del operador ‘:’. Si el pipe aceptara varios parámetros, los separaríamos con ‘:’. Ejemplo: “{{ … | currency:’USD’:false }}”. El valor de un parámetro puede ser una expresión de template válida, una cadena de caracteres o una propiedad/función de un componente. Esto signica que el cambio de formato puede controlarse con data binding (mecanismos que permiten la comu-

122

El gran libro de Angular

nicación entre un componente y su template) de la misma manera en la que controlábamos “fecha1” en el ejemplo anterior. Veamos un ejemplo: 3. En este ejemplo vamos a usar una función de un componente como valor de parámetro de un DatePipe. Está función devolverá ShortDate o FullDate, parámetros válidos para el DatePipe, según el valor de la propiedad “idFormatoFecha”, que podremos modicar mediante un botón. Para ello, añadiremos el siguiente código y lo pondremos a prueba desde el navegador: src/app/app.component.ts export class AppComponent { … idFormatoFecha = true; // true == shortDate ; false == fullDate get formatoFecha()

{ return this.idFormatoFecha ? ‘shortDate’ :

‘fullDate’; } cambiarFormatoFecha() { this.idFormatoFecha = !this.idFormatoFecha; } }

src/app/app.component.html …

Fecha (DatePipe con ‘{{ formatoFecha }}’): {{ fecha1 | date:formatoFecha }}



Por último, comentar que los pipes pueden encadenarse para realizar diversas transformaciones una detrás de otra. El encadenamiento de pipes lo realizaremos usando el operador ‘|’ como separador. Veamos un ejemplo:

El gran libro de Angular

123

4. Para este último ejemplo añadiremos el siguiente código y comprobaremos desde el navegador cómo se aplican los pipes DatePipe y UpperCasePipe uno detrás de otro. src/app/app.component.html

Fecha (DatePipe con ‘fullDate’ y UpperCasePipe): {{ fecha1 | date:’fullDate’ | uppercase }}



124

El gran libro de Angular

031

Pipes: DatePipe, UpperCasePipe y LowerCasePipe

Angular por defecto incorpora los pipes DatePipe, UpperCasePipe, LowerCasePipe, DecimalPipe, CurrencyPipe y PercentPipe para que puedan ser usados desde cualquier template. En este ejercicio veremos cómo usar DatePipe, UpperCasePipe y LowerCasePipe a través de diversos ejemplos. El resto, los veremos en el siguiente ejercicio.

Importante Utilice DatePipe y todo su abanico de parametrizaciones posibles para realizar los cambios de formato de fechas que necesite.

DatePipe DatePipe nos permite formatear fechas. Se usa de la siguiente manera: date_expression | date[:format]

donde: •



date_expression es un objeto fecha, un número (milisegundos respecto fecha UTC epoch [1 de enero de 1970]) o un cadena de caracteres con formato ISO (http://www.w3.org/TR/NOTE-datetime). format es una cadena de caracteres que identica el formato con que el que se quiere visualizar la fecha. Puede contener alguno de los valores predenidos validos: medium, short, fullDate, o una combinación de símbolos (‘y’: año, ‘M’: mes, etc.) para crear nuevos formatos. Consulte https://angular.io/api/ common/DatePipe para más información.

UpperCasePipe UpperCasePipe transforma un texto a mayúsculas. LowerCasePipe LowerCasePipe transforma un texto a minúsculas. Vamos a ver ejemplos de estos pipes. 1. Nos ubicaremos en ej100_angular, y crearemos el proyecto tecleando ng new pipeDisp. Seguidamente lo renombraremos para que haga referencia El gran libro de Angular

125

a nuestro número de ejercicio ejecutando rename pipeDisp 031_ pipeDisp, y nalmente pondremos en marcha la aplicación ejecutando ng serve desde la carpeta 031_pipeDisp. 2. Primero crearemos el componente a partir del cual realizaremos el ejercicio C:\Ej100_angular\031_pipeDisp>ng generate component datePipe

Seguidamente abriremos el proyecto con nuestro editor Atom, y en el template principal de la aplicación pondremos el siguiente código para que cargue nuestro componente. Podremos comprobarlo desde el navegador. src/app/app.component.html

Finalmente añadiremos los ejemplos en el código. Desde el navegador, podremos ver el resultado. src/app/date-pipe/date-pipe.component.ts export class DatePipeComponent implements OnInit { fecha: Date = new Date(1988, 3, 15, 12, 30, 15); //15 de Abril del 1988 12:30:15 … src/app/date-pipe/date-pipe.component.html

DatePipe: ejemplos de uso







126 El gran libro de Angular
{{ fecha }} {{ fecha }}
{{ fecha | date | uppercase}} {{ fecha | date | uppercase}}
{{ fecha | date:’medium’ | lowercase}} {{ fecha | date:’medium’ | lowercase}}
{{ fecha | date:’d/M/y HH:mm:ss’ }} {{ fecha | date:’d/M/y HH:mm:ss’ }}


El gran libro de Angular

127

032

Pipes: DecimalPipe, CurrencyPipe y PercentPipe

En este ejercicio seguiremos analizando los pipes que Angular incorpora. En este caso, analizaremos los pipes DecimalPipe, CurrencyPipe y PercentPipe. Todos ellos parten de un número como valor de entrada. DecimalPipe Nos permite formatear un número como texto. Se usa de la siguiente manera:

A veces, desde una pipe, se usan funcionalidades de otras pipes, como es el caso de CurrencyPipe y PercentPipe respecto a DecimalPipe.

number_expression | number[:digitInfo]

donde: •

Importante

digitInfo es una cadena de texto con el siguiente formato: {minIntegerDigits}.{minFractionDigits}-{maxFractionDigits}

donde: • • •

minIntegerDigitses el número mínimo de enteros que se van a usar. Por defecto vale 1. minFractionDigitses el número mínimo de decimales que se van a usar. Por defecto vale 0. maxFractionDigitses el número máximo de decimales que se van a usar. Por defecto vale 3.

CurrencyPipe CurrencyPipe nos permite formatear un número como moneda. Se usa de la siguiente manera: number_expression | currency[:currencyCode[:symbolDisplay[:digitInfo]]] donde: •

128

currencyCode es el código de moneda ISO 4217, como USD para el dólar y EUR para el euro. El gran libro de Angular

• •

symbolDisplay: con true visualizaremos el símbolo ($ o €), y con false el código (USD o EUR). digitInfo: mirar DecimalPipe para ver su descripción.

PercentPipe Nos permite formatear un número como porcentaje. Se usa de la siguiente manera: number_expression | percent[:digitInfo] donde: •

digitInfo: mirar DecimalPipe para ver su descripción.

Vamos a ver ejemplos de estos pipes. 1. Desde la carpeta del proyecto creado en el anterior ejercicio, creamos el componente. C:\Ej100_angular\031_pipeDisp>ng generate component numberPipes

Seguidamente abriremos el proyecto con nuestro editor Atom, y en el template principal de la aplicación, pondremos el siguiente código para que cargue nuestro nuevo componente. Desde el navegador podremos comprobarlo. src/app/app.component.html

Por último, añadiremos el código en el componente. En el navegador podremos ver el resultado. src/app/number-pipes/number-pipes.component.ts

El gran libro de Angular

129

export class NumberPipesComponent implements OnInit { pi: number = 3.141592; … src/app/number-pipes/number-pipes.component.html

CurrencyPipe, PercentPipe: ejemplos de uso

{{pi}} {{pi}}
{{pi | currency:’EUR’:false}} {{pi | currency:’EUR’:false}}
{{pi | currency:’EUR’:true:’4.3-3’}} {{pi | currency:’EUR’:true:’4.3-3’}}
{{pi | percent}} {{pi | percent}}
{{pi | percent:’4.3-3’}} {{pi | percent:’4.3-3’}}


130

El gran libro de Angular

El gran libro de Angular

131

033

Pipes: Pipes personalizados

Como hemos visto en anteriores capítulos, Angular ofrece un conjunto de pipes que permiten formatear los datos antes de mostrarlos al . Sin embargo, podría pasar que este conjunto de pipes no fuera suciente para realizar los cambios de formato que necesitamos. Por suerte, Angular ofrece las herramientas necesarias para crear nuevos pipes personalizados. En este ejercicio veremos cómo hacerlo. En el ejemplo crearemos un pipe que realice una división entera, o sea, que lleve a cabo una división y, como resultado, devuelva el cociente y resto como números enteros sin decimales. A través del operador “|” obtendrá el dividendo y por parámetro se le pasará el divisor:

Importante Angular ofrece todas la herramientas necesarias para crear pipes según nuestras necesidades. De esta manera podemos centralizar en los pipes todas las tareas de transformación que necesitemos.

number_expression | divisionEntera:divisor Vamos a empezar el ejercicio: 1. Nos ubicaremos en ej100_angular, y crearemos el proyecto tecleando ng new pipePers. Seguidamente lo renombraremos para que haga referencia a nuestro número de ejercicio ejecutando rename pipePers 033_pipePers, y nalmente pondremos en marcha la aplicación ejecutando ng serve desde la carpeta 033_pipePers.

2. Ahora crearemos el nuevo pipe divisionEnteraPipe. Para ello ejecutaremos lo siguiente: C:\Ej100_angular\033_pipePers>ng generate pipe divisionEntera

132

El gran libro de Angular

La anterior ejecución habrá creado los archivos necesarios para el nuevo pipe y añadido una referencia en app.module.tst para que pueda usarse desde cualquier template, aunque, de momento, sin realizar ningún tipo de transformación. Para que se lleve a cabo, tendremos que implementar el código necesario. El desarrollo se realizará íntegramente en el archivo division-entera.pipe.ts. Este archivo lo encontraremos así: src/app/division-entera.pipe.ts import { Pipe, PipeTransform } from ‘@angular/core’;

@Pipe({ name: ‘divisionEntera’ }) export class DivisionEnteraPipe implements PipeTransform {

transform(value: any, args?: any): any { return null; }

}

De forma resumida, podemos denir un pipe como una clase “decorada” con metadatos de pipe. La implementación de cualquier pipe personalizado tiene los siguientes requerimientos: •



La clase del pipe debe implementar el método transform de la interface PipeTransform. Este método toma el valor que “canaliza” y un número variable de parámetros de cualquier tipo, y devuelve un valor transformado. Debe usarse el decorador @Pipe para que Angular sepa que es un pipe. En el decorador, indicaremos el nombre del pipe. Este será el que deberemos usar desde los templates para usarlo.

Una vez analizado el código que se ha generado, seguiremos con la implementación. 3. Añadiremos el siguiente código, que denirá la funcionalidad de nuestro pipe:

El gran libro de Angular

133

src/app/division-entera.pipe.ts … transform(value: number, divisor: string): string { let div = parseFloat(divisor); let cociente = Math.oor(value/div); let resto = value % div;

return “Cociente: “ + cociente + “ # Resto: “ + resto; }

Finalmente, para probar el pipe, añadiremos el siguiente código. Desde el navegador podremos probar nuestro nuevo pipe modicando los valores de dividendo y divisor. src/app/app.component.ts … export class AppComponent { dividendo = 10; divisor = 2; … src/app/app.component.html

Pipes personalizados: divisionEnteraPipe

Dividendo:
Divisor:



Resultado: {{dividendo | divisionEntera: divisor}}



src/app/app.module.ts … import { FormsModule } from ‘@angular/forms’; … @NgModule({ declarations: […], imports: […,FormsModule],…

134

El gran libro de Angular

El gran libro de Angular

135

034

Pipes: Puros e impuros

Existen dos categorías de pipes: puros e impuros. La principal diferencia entre ellos radica en la manera que tiene Angular de gestionar su ejecución. En este sentido, Angular ejecutará un pipe puro cuando detecte cambios en la variable de entrada, o sea, un cambio de valor si la variable es de tipo primitivo (string, number, boolean, symbol), o un cambio de referencia si la variable es una referencia a un objeto (date, array, function, object). Por lo tanto, Angular no ejecutaría un pipe de este tipo si, por ejemplo, la variable de entrada fuera de tipo array y le hubiéramos añadido un elemento. Por el contrario, Angular ejecutará un pipe impuro en cada ciclo de detección de cambios (al interaccionar con cualquier elemento de la aplicación) sin importar si ha habido cambios o no en la variable de entrada o parámetros del pipe. Todos los pipe que habíamos visto hasta ahora eran de tipo puro. De hecho, todo pipe es puro por defecto. Si queremos crear un pipe impuro, deberíamos indicarlo de la siguiente manera:

@Pipe({ name: ‘…’ pure: false }) …

Aunque usar pipes impuros puede parecer más ventajoso, el hecho es que su uso requiere el consumo de muchos más recursos que pueden ralentizar la aplicación. Por tanto, siempre es preferible usar pipes puros. Vamos a realizar un ejercicio que nos ayudará a entender estas diferencias. Crearemos un nuevo pipe, numElem, que devolverá el número de elementos de un array. Usaremos este pipe en un contador que nos indicará el número de elementos de un array al cual podremos añadir elementos desde la misma aplicación.

136

El gran libro de Angular

1. Nos ubicaremos en ej100_angular y crearemos el proyecto tecleando ng new pipePurosImpuros. Seguidamente lo renombraremos para que haga referencia a nuestro número de ejercicio ejecutando rename pipePurosImpuros 034_pipePurosImpuros, y nalmente pondremos en marcha la aplicación ejecutando ng serve desde la carpeta 034_ pipePurosImpuros.

2. Seguidamente crearemos el pipe numElem. Para ello, ejecutaremos el siguiente comando: C:\Ej100_angular\034_pipePurosImpuros>ng generate pipe numElem

y en el archivo num-elem.pipe.ts, añadimos el siguiente código en la función transform(…). src/app/num-elem.pipe.ts … transform(cadena: any[]): number { return cadena.length; }

El resto de código de la aplicación sería el siguiente: src/app/app.component.ts … export class AppComponent { fechas: Date[] = []; anadirFecha() {

this.fechas.push(new Date());

}

}

El gran libro de Angular

137

src/app/app.component.html

Pipes: Puros e Impuros

Contador: {{fechas | numElem}}

{{fecha | date:’medium’}}



Importante Utilice los pipes impuros de forma controlada. Consumen muchos más recursos que los pipes puros y puede afectar negativamente a la experiencia de .

Al probar la aplicación desde el navegador, veremos que el contador no se actualiza al pulsar “Añadir fecha”. El motivo es el comentado al principio del ejercicio: el pipe es puro, y como Angular no detecta cambios en la referencia del array de fechas, cuando se añaden nuevas fechas no ejecuta el pipe y el contador no se actualiza.

Como podrá ver a continuación, podemos solucionar el problema de dos maneras distintas. Aunque la opción preferible será la de declarar el pipe numElem como impuro (opción b) Al hacerlo vemos que el contador ya funciona.

138

El gran libro de Angular

a. Crear un nuevo array de fechas con la nueva fecha añadida, y asignarla a la original. src/app/app.component.ts … fechas: Date[] = []; anadirFecha() { this.fechas.push(new Date()); let fechas2 = this.fechas.slice(); this.fechas = fechas2; } }

b. Declarar el pipe como impuro. src/app/num-elem.pipe.ts … @Pipe({ name: ‘numElem’, pure: false }) …

El gran libro de Angular

139

035

Pipes: Asynipe

Asynipe es un tipo de pipe impuro. Su característica principal es que acepta objetos Promise u Observable como objetos de entrada. En el mundo de las aplicaciones web, la velocidad es esencial, por lo que el uso de programación asíncrona para aprovechar el tiempo y evitar esperas innecesarias es imprescindible. Promise y Observable son dos de las principales herramientas que tenemos para gestionar este tipo de programación. Consulte los capítulos 51, 52 y 53 para más información.

Importante El uso de Asynipe, aparte de permitirnos ahorrar código, nos ofrece mayor seguridad al realizar de forma automática acciones como “unsubscribe” sobre los observables, que si no se realizaran, podrían provocar problemas de Memory Leaks.

En este ejercicio veremos como Asynipe nos facilita el uso de estas herramientas. Crearemos una aplicación primero sin usar Asynipe y luego empleándolo. La aplicación pondrá en marcha dos temporizadores de 2 y 4 segundos, respectivamente. Al terminar, cada uno de ellos devolverá un texto que acabaremos visualizando por el template. El primer temporizador será controlado mediante Promise y el segundo mediante Observable. 1. Nos ubicaremos en ej100_angular, y crearemos el proyecto tecleando ng new pipeAsynipe. Seguidamente lo renombraremos para que haga referencia a nuestro número de ejercicio ejecutando rename pipeAsynipe 035_pipeAsynipe, y nalmente pondremos en marcha la aplicación ejecutando ng serve desde la carpeta 035_pipeAsynipe.

2. Seguidamente añadiremos el código del ejemplo. En esta primera versión no usaremos Asynipe.

140

El gran libro de Angular

src/app/app.component.ts … import { Observable } from ‘rxjs/Observable’; import { Subscription } from “rxjs/Subscription”;

@Component({…}) export class AppComponent { promiseData:string; observableData:string; observableSubs: Subscription = null;

getPromise(){ return new Promise<string>(function(resolve, reject) { setTimeout(() => {resolve(“Timer1 nalizado”);}, 2000); }); } getObservable() { return new Observable<string>(observer => { setTimeout(() => {observer.next(“Timer2 nalizado”);}, 4000); }); } constructor() { this.getPromise().then( v => this.promiseData = v ); this.observableSubs = this.getObservable() .subscribe( v => this.observableData = v ); } ngOnDestroy(){ if (this.observableSubs) this.observableSubs. unsubscribe();

}

}

El gran libro de Angular

141

src/app/app.component.html

Pipes: Asynipe 76n8

PromiseData: {{ promiseData }}

ObservableData: {{ observableData }}



Una vez añadido el código, podremos comprobar su funcionamiento en el navegador. Por pantalla veremos el texto devuelto por los temporizadores a medida que terminen. La secuencia sería la que aparece en las imágenes. Recargando la página con F5, podremos reactivar los temporizadores.

3. Seguidamente modicaremos el código para que se haga uso de Asynipe. src/app/app.component.ts

142

El gran libro de Angular

… export class AppComponent { promiseObj: Promise<string>; observableObj: Observable<string>;

getPromise(){…} getObservable() {…}

constructor() { this.promiseObj = this.getPromise(); this.observableObj = this.getObservable(); } }

src/app/app.component.html

Pipes: Asynipe 76n8

PromiseData: {{ promiseObj | async }}

ObservableData: {{ observableObj| async }}



Como podemos observar, a Asynipe le podemos pasar directamente los objetos Promise y Observable, por lo que ya no es necesario extraer los valores que devuelven y exponerlos en variables para que puedan ser mostrados en el template mediante interpolación (data binding). Por otra parte, tampoco hace falta hacer el “subscribe” y “unsubscribe” al objeto Observable. Asynipe se encarga de hacerlo por nosotros.

El gran libro de Angular

143

036

Pipes: JsonPipe

JsonPipe es otro pipe de tipo impuro. Convierte un objeto a cadena JSON. Se usa de la siguiente manera: expression | json JsonPipe se usa en multitudes de situaciones, sin embargo, cabe destacar su uso en procesos de depuración de código, ya que permite analizar el contenido de cualquier objeto para comprender el comportamiento del código y buscar posibles errores. En este ejercicio crearemos una aplicación que nos ayudará a entender el funcionamiento de JsonPipe. La aplicación tendrá dos clases, Libro y Escritor, a partir de las cuales se crearán diversos objetos. Luego, la misma aplicación mostrará por el navegador el contenido de todos estos objetos usando JsonPipe.

Importante JsonPipe permite transformar un objeto a cadena JSON. Esto puede ser muy útil en tareas de depuración de código.

1. Primero de todo nos ubicaremos en ej100_angular, y crearemos el proyecto tecleando ng new pipeJsonPipe. Seguidamente lo renombraremos para que haga referencia a nuestro número de ejercicio ejecutando rename pipeJsonPipe 036_pipeJsonPipe, y nalmente pondremos en marcha la aplicación ejecutando ng serve desde la carpeta 036_pipeJsonPipe.

2. Ahora abriremos el proyecto con Atom, y crearemos las clases Libro y Escritor. Para ello, nos situaremos sobre la carpeta app, pulsaremos botón derecho, y seleccionaremos “New File”. La clase Libro la crearemos como “libro.ts” y la clase Escritor como “escritor.ts”.

144

El gran libro de Angular

3. Una vez creados los cheros de las clases, añadiremos su código: src/app/libro.ts export class Libro { constructor(public titulo:string, public tematica:string) { } } src/app/escritor.ts import {Libro} from ‘./libro’;

export class Escritor { constructor(public id:number, public nombre:string,

public

fecha:Date, public libros:Libro[]) { } }

Seguidamente crearemos los objetos en el componente. Para ello, añadiremos el siguiente código:

El gran libro de Angular

145

src/app/app.component.ts … import {Escritor} from ‘./escritor’; import {Libro} from ‘./libro’;

@Component({… }) export class AppComponent {

libro1: Libro = new Libro(‘Mucho ruido y pocas nueces’, ‘Comedia’); libro2: Libro = new Libro(‘Romeo y Julieta’, ‘Drama’); librosArray: Libro[] = [this.libro1, this.libro2];

escritor = new Escritor (1, ‘William Shakespeare’, new Date(1564, 3, 26), this.librosArray); }

Y, nalmente, añadiremos el código en el template que nos permitirá visualizar el contenido de todos esos objetos. Usaremos JsonPipe para visualizar el contenido de un objeto (Libro), de un array de objetos (Libros) y de un objeto de objetos (Escritor). src/app/app.component.html

Pipes: JsonPipe 4l4k42

JsonPipe sobre un libro (objeto): {{libro1 | json}} <pre> {{libro1 | json}} JsonPipe sobre el array de libros (array de objetos)): {{librosArray | json}} o {{escritor.libros | json}} <pre>{{escritor.libros | json}} JsonPipe sobre escritor (objeto de objetos): {{escritor | json}} <pre>{{escritor | json}}

146

El gran libro de Angular

En el anterior código, cabe destacar el uso de la directiva ngNonBindable. Esta directiva le indica a Angular que no compile el contenido del tag. Esto nos permite mostrar por pantalla el literal “{{…}}” sin que sea procesado por Angular. Por otra parte, hay que destacar el uso del tag <pre>, que nos permite visualizar la cadena JSON con saltos de línea para facilitar su análisis. 4. Desde el navegador podremos ver el resultado de todo el código anterior

El gran libro de Angular

147

037

Modelos de datos y mock data (datos simulados) (parte I)

Tal como habíamos visto en el capítulo “005 TypeScript. Introducción…”, el lenguaje de programación TypeScript nos permite realizar una programación JavaScript orientada a objetos con código simple y limpio. Esto signica que podremos aplicar una programación orientada a objetos en nuestras aplicaciones Angular y aprovecharnos de todas la ventajas que esto supone. De forma resumida podríamos denir la programación orientada a objetos como un método de implementación en el que los programas se organizan como colecciones cooperativas de objetos, cada uno de los cuales representan una instancia de alguna clase. Las clases representan entidades o conceptos. Cada una de ellas es un modelo que dene un conjunto de variables y métodos. Además, todas ellas son de una jerarquía de clases unidas mediante relaciones de herencia.

Importante La programación orientada a objetos aplicada en nuestras aplicaciones Angular mejorará su reusabilidad, mantenimiento y abilidad.

Algunas de las ventajas de la programación orientada a objetos son: • •



Reusabilidad. El diseño adecuado de las clases permite que se puedan usar en distintas partes del programa y en otros proyectos. Mantenimiento. Los programas orientados a objetos son más sencillos de leer y comprender, ya que permiten ocultar detalles de implementación dejando visibles solo aquellos detalles más relevantes. Todo esto facilita el trabajo de realizar modicaciones y detectar posibles problemas. Fiabilidad. Al dividir el problema en partes más pequeñas permite que podamos probarlas de manera independiente y aislar fácilmente los posibles errores que puedan surgir.

En este ejercicio veremos cómo enfocar un programa Angular a la programación orientada a objetos trabajando con modelos de datos. Primero crearemos una aplicación Angular con un único componente Biblioteca que visualizará el contenido de una variable interna de tipo array con distintos elementos que serían los libros. 148

El gran libro de Angular

En la segunda parte de este ejercicio modicaremos la aplicación creando el modelo de datos Libro, reestructurando el código y el mock data (datos simulados), y comentando las ventajas de esos cambios. 1. En primer lugar, nos ubicaremos en Ej100_angular y crearemos el proyecto tecleando ng new dataModels. Seguidamente lo renombraremos para que haga referencia a nuestro número de ejercicio, ejecutando rename dataModels 037_dataModels y, nalmente, pondremos en marcha la aplicación ejecutando ng serve desde la carpeta 037_dataModels.

2. Ahora crearemos el componente biblioteca mediante el comando siguiente: C:\Ej100_angular\037_dataModels>ng generate component biblioteca

Seguidamente abriremos el proyecto con Atom y editaremos el componente biblioteca añadiendo la variable con los libros: src/app/biblioteca/biblioteca.component.ts … export class BibliotecaComponent implements OnInit { libros = [{ “id”: 1, “titulo”: “El Quijote”, “autor”: “Cervantes” },{ “id”: 2, “titulo”: “Hamlet”, “autor”: “Shakespeare” }]; …

El siguiente paso será modicar el template del componente biblioteca para visualizar el contenido de la variable anterior. Para ello abriremos biblioEl gran libro de Angular

149

teca.component.html y sustituiremos todo el código que tenga por el siguiente: src/app/biblioteca/biblioteca.component.html

Biblioteca: 1k601p

  • {{libro.titulo | uppercase}} 3zn1c

    {{libro.autor}}



En este código aparecen ciertos elementos de Angular como son las directivas (“*ngFor”) y los pipes (“...libro.titulo | uppercase…”). Para más información, consulte los capítulos dedicados a las directivas y a los pipes. 3. Finalmente, solo faltará que nuestra aplicación cargue el componente biblioteca en la página principal. Para ello, simplemente añadiremos la referencia a nuestro componente en el template del componente principal de la aplicación: app.component.html. Sustituiremos su contenido por el siguiente:

4. En este punto, desde el navegador (http://localhost:4200) ya podremos ver que nuestra aplicación muestra los libros de la biblioteca.

150

El gran libro de Angular

038

Modelos de datos y mock data (datos simulados) (parte II)

Vamos a continuar con la aplicación que habíamos creado en el anterior ejercicio. En este ejercicio crearemos el modelo de datos Libro añadiendo las modicaciones necesarias, reestructurando el código y mock data (datos simulados), comentando las ventajas de esos cambios. 1. En primer lugar, abriremos el proyecto 037_ dataModels con el editor (Atom) y pondremos en marcha la aplicación ejecutando ng serve desde línea de comandos y dentro de la carpeta 037_dataModels.

Importante El uso de variables tipadas (con tipo de datos denido) de TypeScript aporta mayor veracidad al código. Permite la detección de errores en el tiempo de compilación.

2. Ahora crearemos el modelo de datos Libro. Desde el editor Atom nos situaremos en la carpeta app, pulsaremos el botón derecho del ratón, seleccionaremos New File, y crearemos el chero con el nombre libro.model.ts. Dentro del nuevo chero añadiremos el siguiente código: src/app/libro.model.ts export class Libro { id: number; titulo: string; autor: string; }

Como vemos, un modelo de datos básicamente es una clase en JavaScript. También podemos observar cómo, gracias a TypeScript, podemos denir el tipo (number, string, etc.) de cada una de las distintas propiedades del modelo. Esto permitirá al compilador validar nuestro código y asegurarse de que usamos esas propiedades de manera adecuada. 3. A continuación, modicaremos el componente biblioteca para que haga uso del nuevo modelo de datos Libro. El cambio será muy sencillo, simplemente

El gran libro de Angular

151

añadiremos la referencia al modelo de datos Libro, y le diremos a TypeScript que trate la variable libros como una cadena de Libros: src/app/biblioteca/biblioteca.component.ts import { Component, OnInit } from ‘@angular/core’; import { Libro } from ‘../libro.model’; … export class BibliotecaComponent implements OnInit { libros: Libro[] = [{ “id”: 1, “titulo”: “El Quijote”, …

Como hemos comentado en el punto anterior, al denir un tipo para la variable libros (en este caso, cadena de Libros), el compilador es capaz de validar que se esté usando esta variable de forma correcta. Si, por ejemplo, modicáramos la propiedad “titulo” por “nombre”, de alguno de los libros el compilador daría error. src/app/biblioteca/biblioteca.component.ts … libros: Libro[] = [{ “id”: 1, “nombre”: “El Quijote”, …

4. Desde el navegador (http://localhost:4200) podremos vericar que todo funciona.

152

El gran libro de Angular

Normalmente, una aplicación Angular haría una llamada a un web service (API) para obtener los datos que necesita que, en el caso de nuestra aplicación, serían los libros. Por lo tanto, es una buena práctica quitar los datos de prueba (o mock data) de nuestros modelos y componentes y dejarlos en cheros aparte. Siguiendo esta recomendación, vamos a realizar cambios en nuestra aplicación. 5. Desde el editor Atom, nos situaremos en la carpeta app, pulsaremos el botón derecho del ratón, seleccionaremos New File, y crearemos el chero mocks.ts. Dentro, añadiremos lo siguiente: src/app/mocks.ts import { Libro } from ‘./libro.model’; export const LIBROS: Libro[] = [{ “id”: 1, “titulo”: “El Quijote”, “autor”: “Cervantes” },{ “id”: 2, “titulo”: “Hamlet”, “autor”: “Shakespeare” }];

6. Finalmente modicaremos el componente biblioteca para que cargue los datos mock desde ese chero: src/app/biblioteca/biblioteca.component.ts import import import … export

{ Component, OnInit } from ‘@angular/core’; { Libro } from ‘../libro.model’; { LIBROS } from ‘../mocks’; class BibliotecaComponent implements OnInit {

libros: Libro[]; … ngOnInit() { this.libros = LIBROS; } }

El gran libro de Angular

153

7. Desde el navegador (http://localhost:4200) podremos vericar que todo funciona bien.

154

El gran libro de Angular

039

Librerías. Enumeración de librerías

Al igual que en otros lenguajes, las librerías, entre otras muchas ventajas, nos permiten organizar el código y reutilizarlo en otras aplicaciones. En este sentido, Angular utiliza un conjunto de librerías “de serie” que aportan funcionalidad en diferentes aspectos como veremos a continuación, pero, además, facilita el uso de otras librerías de terceros que pueden aportarnos soluciones que simplemente hemos de importar y utilizar. Las librerías más importantes de Angular y su cometido son las siguientes: @angular/animations

@angular/cli

@angular/common @angular/compiler

@angular/compiler_cli @angular/core

Importante Importe solo las librerías que necesite para optimizar el código y hacer que la aplicación sea más eciente al cargar solo los recursos que se vayan a utilizar.

Permite realizar animaciones similares a las realizadas con CSS (efectos, transiciones entre páginas, etc.) integrando la lógica de animación con el resto de códigos de la aplicación. Permite trabajar con Angular-CLI inicializando, desarrollando y manteniendo aplicaciones Angular a partir de la creación de componentes, directivas, etc. Proporciona directivas, pipes y servicios comúnmente utilizados. Librería del compilador que permite convertir nuestro código y nuestras plantillas antes de ejecutar y representar la aplicación. Librería del compilador para Node.js invocada por los comandos build y serve de Angular CLI. Es el principal repositorio de fuentes de Angular. Incluye todos los decoradores de metadatos, componentes, directivas, inyección de dependencia, etc. Imprescindibles para la creación de aplicaciones.

El gran libro de Angular

155

@angular/forms

@angular/http @angular/language-service

@angular/platformbrowser

@angular/platformbrowser-dynamic

@angular/router

Proporciona directivas y servicios para crear forms tanto template-driven como reactivedriven (vistos más adelante). Permite usar http. Permite analizar las plantillas de los componentes proporcionando sugerencias, chequeo de sintaxis, chequeo de errores, etc., detectando automáticamente el tipo de archivo tratado. Librería usada para navegadores web que ayuda a procesar el DOM e incluye el método bootstrapStatic() para arranque de aplicaciones precompiladas con AOT. Librería usada para navegadores web que incluye proveedores y métodos para compilar y ejecutar la aplicación en el cliente utilizando el compilador JIT y que contiene el código del lado del cliente procesando las plantillas (enlaces, componentes, etc.), además de la inyección de dependencia reexiva. Librería que permite navegar entre páginas de la aplicación al cambiar el URL del navegador.

A lo largo del libro, tendremos la oportunidad de trabajar con diversas librerías. En este ejercicio, vamos a realizar un ejemplo sencillo del uso de animaciones como excusa para utilizar la librería de @angular/animations. 1. En primer lugar, nos ubicaremos en ej100_angular y crearemos el proyecto libAnima mediante el comando ng new: C:\Ej100_angular>ng new libAnima

156

El gran libro de Angular

Seguidamente, renombraremos el proyecto para que haga referencia a nuestro número de ejercicio. Para ello, estando ubicados en el directorio Ej100_ angular, escribiremos lo siguiente: C:\Ej100_angular>rename libAnima 039_libAnima A continuación, nos ubicaremos en 039_libAnima y arrancaremos la aplicación para comprobar cómo funciona en nuestro navegador. Para ello, teclearemos lo siguiente: C:\Ej100_angular>cd 039_libAnima C:\Ej100_angular\039_libAnima>ng serve

Ahora, abrimos el proyecto con nuestro editor (en nuestro caso, usamos Atom) y modicamos el archivo app.component.html para que incluya un div denominado caja, el evento click que llame a la función cambioEstado() y un trigger asociado a la variable estado.

2. Seguidamente, modicaremos el archivo app.module.ts para importar el módulo BrowserAnimationsModule.

El gran libro de Angular

157

3. A continuación, modicaremos el archivo app.component.ts para importar las siguientes funciones contenidas en la librería @angular/ animations: import { trigger, state, style, animate, transition } from ‘@ angular/animations’;

Por otra parte, deniremos un trigger denominado estado que contempla dos estados: activo e inactivo. Por tanto, modicaremos el decorador @Component para denir la animación y la clase AppComponent para poner el título”‘039 libAnima”, denir la variable estado y denir la función cambioEstado() que permita alternar el valor de la variable estado entre los valores activo e inactivo. Como puede observarse, cada estado dene un color de fondo, un color para el texto y una escala (p. ej., scale(1)) además de un efecto en la transición entre estados (ease-in, ease-out ) que se realiza durante un tiempo determinado (1.000 ms).

4. Por último, deniremos los estilos que usará nuestro div modicando el chero styles.css.

158

El gran libro de Angular

5. Guárdelo todo y abra su navegador para teclear el URL http://localhost:4200/ y comprobar el resultado.

6. Haga clic sobre el div y observe cómo cambia de tamaño y color.

El gran libro de Angular

159

040

One Way Data Binding (hacia el DOM): Interpolación, Property Binding y Class Binding

Cuando un navegador web carga un documento (vista), genera una estructura de objetos que llamamos DOM. El DOM puede alterarse mediante JavaScript para cambiar dinámicamente los contenidos y el aspecto de la página. El Data Binding es un concepto primordial en Angular. Permite denir la comunicación entre un componente y el DOM, lo que hace que sea muy fácil denir aplicaciones interactivas sin preocuparnos de la actualización de datos en DOM (push) o la obtención de datos desde el DOM (pull).

Importante Interpolación, Property Binding y Class Binding son distintos mecanismos de comunicación de datos desde JavaScript (TypeScript compilado) hacia HTML, pero no para el sentido contrario.

Hay tres tipos distintos de Data Binding que dieren en la forma que uyen los datos. Y, para cada uno de ellos, Angular ofrece distintos mecanismos:

• • •

160

One Way Data Binding (del componente al DOM): Interpolación, Property Binding y Class Binding. One Way Data Binding (del DOM al componente): Event Binding y $event. Two Way Data Binding (del componente al DOM y viceversa): FormsModule y [(ngModel)].

El gran libro de Angular

En este ejercicio y en los dos siguientes, veremos ejemplos de todos ellos. Crearemos una aplicación que mostrará un artículo con una disponibilidad determinada de stock, y una serie de opciones para añadir/quitar unidades del “carrito de compra”. Esta aplicación se irá desarrollando a lo largo de estos tres ejercicios haciendo uso de todos estos mecanismos. 1. Nos ubicaremos en ej100_angular, y crearemos el proyecto tecleando ng new dataBinding. Seguidamente lo renombraremos para que haga referencia a nuestro número de ejercicio ejecutando rename dataBinding 040_dataBinding, y nalmente pondremos en marcha la aplicación ejecutando ng serve desde dentro la carpeta 040_dataBinding. A continuación, abriremos el proyecto con Atom.

2. Seguidamente añadiremos los links de Bootstrap (https://v4-alpha. getbootstrap.com) para poder hacer uso de sus hojas de estilo. Consulte el ejercicio “087 Bootstrap Documentacion” para más información. 3. La interpolación es la forma más sencilla de visualizar propiedades de un componente en su template. Solamente hace falta poner el nombre de la propiedad entre {{ … }} en el template. Mediante el siguiente código, crearemos nuestro artículo en el componente principal de la aplicación, y con interpolación, mostraremos sus datos en el template. La imagen referenciada en el artículo, “assets/old-books.jpg”, la encontrará en las fuentes del ejercicio. Debe dejarla en la carpeta assets del proyecto. src/app/app.component.ts … export class AppComponent { Libro = {“titulo”: “Hamlet”, “autor”: “William Shakespeare”, “precio”: 21.30, “stock”: 5, “cantidad”: 0, “imagen”: “assets/oldbooks.jpg”}; } src/app/app.component.html

El gran libro de Angular

161

{{Libro.titulo}} c1ix

{{Libro.autor}} 6h1u1q
  • Unidades disponibles: {{Libro. stock}}
  • Precio: {{Libro.precio | currency:’EUR’:true}}


4. Cuando necesitemos enlazar propiedades de componente a propiedades de elementos del DOM podemos usar Property Binding como alternativa a la interpolación (que también podría usarse en estos casos). Para usarlo pondremos la propiedad del elemento del DOM entre “[…]” asignándole la propiedad del componente. Continuando nuestro ejercicio, haremos uso de Property Binding para visualizar la imagen del artículo: src/app/app.component.html … ”Imagen


5. Class binding nos permite especicar una clase CSS para añadir a un elemento del DOM si una propiedad de un componente es true. Su sintaxis es similar a la de “Property binding”, con la diferencia que hay que añadir “class.” delante la clase CSS, y que la propiedad del componente debe ser tipo booleano. Para terminar el ejercicio, haremos uso de Class Binding para añadir la clase CSS “aviso” (poner letras en rojo) al indicador de “unidades disponibles” en el caso de que no haya stock. Para ello, añadiremos: src/app/app.component.css .aviso{ color: red; } src/app/app.component.html

162

El gran libro de Angular

Descargado en: ey books.com …
  • Unidades disponibles: {{Libro.stock}}


  • 6. Desde el navegador (http://localhost:4200/) podrá ver el estado de nuestra aplicación. Puede cambiar valores del artículo, incluido poner a 0 “Libro. enStock”, y comprobar cómo se actualiza la vista.

    El gran libro de Angular

    163

    041

    One Way Data Binding (desde el DOM): Event Binding y $event

    En este ejercicio analizaremos los mecanismos que ofrece Angular para el envío de datos del DOM al componente: Event Binding y $event. Son mecanismos de comunicación de un solo sentido, de la vista al componente, por eso los llamamos mecanismos de One Way Data Binding. Event Binding nos permite capturar cualquier evento estándar del DOM (hacer clic en un botón, pasar el ratón por encima de determinado elemento, etc.) y transmitirlo al componente para que realice las acciones que convengan. Para hacer uso de Event Binding simplemente pondremos el evento que queramos controlar entre paréntesis y sin “on” de delante, y lo asignaremos a una función del componente. Veamos unos ejemplos:

    Importante Con Event Binding podemos gestionar cualquier evento estándar del DOM desde nuestros componentes. Con el uso de $event podemos tener al objeto event para tener más detalle del evento que queramos gestionar.



    Algunas veces necesitaremos información adicional en relación al evento que estamos controlando, por lo que necesitaremos tener al objeto event que se haya producido. Este procedimiento lo haremos pasando el objeto event al método de nuestro componente con $event. Veamos un ejemplo de cómo usarlo en el caso que quisiéramos saber qué tecla se ha pulsado al producirse un evento de tecla pulsada (Keydown): funcionY(event) {

    console.log(“Tecla pulsada: “ + event.keyCode); }

    Continuando la aplicación que habíamos empezado en el anterior ejercicio, le añadiremos las opciones para añadir/quitar unidades del “carrito de compra” utilizando los mecanismos Event Binding y $event. 1. Desde línea de comandos nos situaremos en ej100_angular/040_ dataBinding, y ejecutaremos la aplicación con ng serve. A continuación, abriremos el proyecto con Atom. 2. En el template del componente añadiremos los botones de añadir/quitar unidades del “carrito de compra” junto a un visor con la cantidad de unidades 164

    El gran libro de Angular

    que tenemos en el carrito. Mediante Event Binding gestionaremos el evento click sobre los botones. Este es el código que hay que añadir: src/app/app.component.ts export class AppComponent { … downCantidad(libro){ if (libro.cantidad > 0 ) libro.cantidad--; } upCantidad(libro){ if (libro.cantidad < libro.stock ) libro.cantidad++; } } src/app/app.component.html …
    {{Libro.cantidad}}


    Como vemos en el navegador, los botones de quitar/añadir unidades funcionan correctamente. Sin embargo, podemos añadir una mejora. Podemos hacer uso de Property Binding, visto en el anterior capítulo, para deshabilitar los botones cuando al hacer clic sobre ellos no tenga ningún efecto debido a las restricciones que hemos puesto en downCantidad(libro) y upCantidad(libro). Esto lo realizaremos añadiendo el siguiente código: src/app/app.component.html {{Libro.cantidad}}

    Finalmente, para ver un ejemplo de uso de $event junto a Event Binding, capturaremos el evento de movimiento de ratón sobre la imagen e indicaremos por log en qué posición se encuentra el ratón (recuerde que para ver los logs debe hacer clic sobre “Más Herramientas/Herramientas para desarrolladores” del menú de Google Chrome). Para ello, añadiremos el siguiente código:

    El gran libro de Angular

    165

    src/app/app.component.ts export class AppComponent { … getCoord(event) {

    console.log(event.clientX + “, “ + event.

    clientY); } } src/app/app.component.html ”Imagen

    Desde el navegador (http://localhost:4200/) podrá realizar pruebas de la aplicación. Pulsando los botones podrá comprobar cómo se quitan/añaden unidades en el “carrito”, podrá comprobar cómo se deshabilitan los botones cuando la cantidad es 0 o cuando se llega al stock disponible y por último podrá ver la posición del ratón cuando pase el puntero por encima de la imagen.

    166

    El gran libro de Angular

    042

    Two Way Data Binding (hacia-desde el DOM): FormsModule y [(ngModel)]

    Hay ciertas situaciones en las que necesitaremos comunicación entre componente y DOM en los dos sentidos al mismo tiempo. Por ejemplo, este sería el caso de un elemento “input” del DOM. Por una parte, necesitaríamos que se actualizara con el valor de una determinada propiedad del componente y, por la otra, necesitaríamos que escuchara eventos (introducción de datos por parte del ) actualizando el valor de esa propiedad. Combinando los mecanismos de One Way Data Binding que hemos visto anteriormente podríamos conseguir ese resultado. Veamos cómo podríamos conseguirlo combinando Property Binding y Event Binding en un elemento “input” destinado a la entrada de un nombre de :

    Importante Con [(ngModel)] podemos realizar Two Way Data Binding, cosa que signica que una propiedad de componente se mantendrá sincronizada tanto si se modica desde dentro del componente (JavaScript) como si se hace desde la vista (HTML).



    Sin embargo, Angular nos ofrece una mejor manera de hacerlo. Se trata de ngModel. Veamos cómo quedaría el código anterior con ngModel:

    Como vemos, su sintaxis es mucho más sencilla y clara. Únicamente hay que tener en cuenta que deberemos importar a nuestro proyecto el módulo FormsModule para poder hacer uso de ngModel. Por otra parte, hay que tener en cuenta que, a diferencia de los mecanismos de One Way Data Binding, ngModel solo acepta propiedades de datos de componente. Si lo inicializáramos con una función de componente (p. ej.: [(ngModel)]=”nombreCompleto()”) se produciría un error.

    El gran libro de Angular

    167

    Para continuar la aplicación que habíamos empezado en los anteriores ejercicios, vamos a ver cómo usaríamos ngModel al añadir un nuevo elemento “input” para poder introducir directamente la cantidad de unidades del artículo que deseemos. 1. Desde línea de comandos nos situaremos en ej100_angular/040_dataBinding, y ejecutaremos la aplicación con ng serve. A continuación, abriremos el proyecto con Atom. 2. Abriremos app.module.ts e importaremos el modulo FormsModule. También será necesario ponerlo en “imports:[..]” de @NgModule para que pueda usarse en toda la aplicación. src/app/app.module.ts import { BrowserModule } from ‘@angular/platform-browser’; import { NgModule } from ‘@angular/core’; import { FormsModule } from ‘@angular/forms’;

    import { AppComponent } from ‘./app.component’;

    @NgModule({ declarations: [ AppComponent ], imports: [ BrowserModule, FormsModule ], providers: [], bootstrap: [AppComponent] }) export class AppModule { }

    A continuación, sustituiremos el visor de cantidad “{{Libro.cantidad}}” que teníamos en la vista por un elemento “input” que nos permita introducir la cantidad manualmente. Este elemento “input” lo vincularemos a la propiedad “Libro.cantidad” mediante [(ngModel)]. Esto lo realizaremos añadiendo el siguiente código:

    168

    El gran libro de Angular

    src/app/app.component.html …

    Desde el navegador (http://localhost:4200/) podrá comprobar cómo se produce el Two Way Data Binding, o sea, la sincronización de datos en los dos sentidos, entre la propiedad “Libro.cantidad” del componente y el nuevo campo cantidad de la vista:

    a. Si a través del elemento “input” modica la cantidad a un valor igual o superior al stock (5), verá como se deshabilita el botón de incrementar cantidad que se enlaza directamente con la propiedad “Libro.cantidad” del componente. Lo mismo pasará con el botón decrementar cantidad si introduce un valor igual o inferior a 0. b. Por otra parte, si usa los botones de decrementar/incrementar cantidad verá como el elemento “input” muestra el nuevo valor de la propiedad “Libro. cantidad” del componente.

    El gran libro de Angular

    169

    043

    Routing: Introducción y conguración básica (parte I)

    Como todos sabemos, la navegación web se realiza mediante la siguiente serie de acciones: •

    • •

    Si introducimos una dirección URL en la barra de direcciones del navegador, cambiaremos de página. Si hacemos clic en un vínculo de una página, cambiaremos de página. Si hacemos clic sobre los botones de avance y retroceso del navegador, navegaremos hacia atrás y hacia delante a través del historial de páginas que haya visto.

    Importante El servicio Router nos servirá para gestionar las rutas y sus vistas asociadas a nuestra aplicación.

    Toda aplicación Web se adapta a esta forma de navegación a través de algún sistema para gestionar sus rutas (direcciones URL) y vistas asociadas (páginas HTML). En el caso de Angular, esta gestión la haremos con el servicio Angular Router. El servicio Router no es accesible por defecto. Tiene su propio paquete sobre el cual deberemos realizar la siguiente importación:

    import { RouterModule, Routes } from ‘@angular/router’;

    Las rutas que gestionaremos con Angular Router serán relativas a una ruta raíz. Esta la conguraremos con “ 170

    El gran libro de Angular

    El servicio Router necesita que le indiquemos una conguración de rutas con la que trabajar. Esta la realizaremos en dos pasos: 1. Creación de la cadena de rutas donde indicaremos la asociación “ruta · componente”: const appRoutes: Routes = [ { path: <path1>, component: }, { path: <path2>, component: }, ..., { path: ‘’, redirectTo: <pathX>, pathMatch: ‘full’ }, { path: ‘**’, component: }];

    2. Asignación de la cadena de rutas al servicio Router mediante el método RouterModule.forRoot(Routes). La conguración indica qué componentes deben visualizarse por el navegador para distintos path de ruta. Y esto es lo que realiza el servicio Router. Cuando en la barra de direcciones del navegador entremos una dirección URL determinada, el servicio intentará hacer “match” de esa dirección con los path de rutas conguradas. Si lo consigue, mostrará el componente que corresponda. Esto signica que para una situación como la siguiente, el servicio Router visualizaría el componente “ListaComponent”.

    Dirección URL

    Conguración de rutas

    Componente seleccionado

    localhost:4200/

    const appRoutes: Routes = [

    ListaComponent

    { path: ‘’, component:ListaComponent },…

    En la cadena de rutas de ejemplo que hemos visto antes, aparecen dos path con unas características particulares: •

    ‘’: El servicio Router seleccionará esta ruta cuando el URL este vacía (p. ej., “localhost:4200/”). Normalmente esta situación sucederá al acceder a la aplicación por primera vez. El gran libro de Angular

    171



    ‘**’: El servicio Router seleccionará esta ruta cuando el URL no coincida con ninguna conguración anterior.

    Para redireccionar rutas haremos uso de redirecTo. En el ejemplo que veremos más adelante, se realizará una redirección a otra ruta en el caso que el URL esté vacío (“http://localhost:4200”). Cuando se usa el redirecTo, es obligatorio añadir un valor para pathMatch para indicar al servicio cómo debe realizar el “match” de un URL con el path de ruta. El servicio Router siempre recorre la conguración de rutas de arriba abajo. Por lo tanto, es importante el orden de las rutas en la conguración. Siempre deberíamos poner las más especícas arriba y abajo las más generales. Esto implica que la conguración de path ‘**’, por su signicado, siempre tiene que estar en última posición, ya que el servicio Router ignorará cualquier otra conguración que haya por debajo. Una vez el servicio Router haya seleccionado el componente adecuado, lo visualizará por pantalla. Concretamente lo situará donde se encuentre la etiqueta router-outlet:

    Con una conguración de rutas básica como la que hemos visto, solamente tendremos una etiqueta “router-outlet” en el template principal de la aplicación. Sin embargo, tal como veremos más adelante, podríamos tener rutas anidadas en la conguración y, en ese caso, tendríamos varias etiquetas router-outlet. Como puede observar, la navegación por la aplicación consistiría en pasar de una vista a otra sin salir nunca de la página HTML que tuviera la etiqueta “router-outlet”. Por tanto, realmente estaríamos navegando en una aplicación de una sola 172

    El gran libro de Angular

    página o SPA (single-page application), concepto del que habíamos hablado en el capítulo 02 “Introducción a las aplicaciones SPA”. Consulte ese capítulo si desea más información.

    El gran libro de Angular

    173

    044

    Routing: Introducción y conguración básica (parte II)

    Una vez vista la introducción al servicio Router, vamos a crear una aplicación para poner en práctica todo lo aprendido. La aplicación consistirá en un sencillo gestor de Libros y Autores. Tendremos una vista libros y una para autores, y pasaremos de una a otra cambiando el URL de la barra de direcciones del navegador.

    Importante Las rutas de la conguración siempre deben ordenarse de más especícas a más genéricas. En este sentido, siempre debe situarse la conguración “**” (cualquier URL) al nal de todo.

    1. Nos ubicaremos en ej100_angular, y crearemos el proyecto tecleando ng new routing. Seguidamente lo renombraremos para que haga referencia a nuestro número de ejercicio ejecutando rename routing 044_routing, y nalmente pondremos en marcha la aplicación ejecutando ng serve desde la carpeta 044_routing. A continuación, abriremos el proyecto con el editor Atom.

    2. Seguidamente añadiremos los links de Bootstrap (https://v4-alpha.getbootstrap. com) en index.html para poder hacer uso de sus hojas de estilo. Consulte “087 Bootstrap. Introducción” para obtener más información. 3. Desde la línea de comandos, crearemos los componentes LibroLista, AutorLista y NotFound con los que trabajará el servicio Router. El componente NotFound se visualizará por pantalla cuando el servicio Router no pueda resolver la ruta. C:\Ej100_angular\044_routing>ng generate component libroLista C:\Ej100_angular\044_routing>ng generate component autorLista C:\Ej100_angular\044_routing>ng generate component notFound

    174

    El gran libro de Angular

    En este punto, desarrollaremos el componente libroLista. Para ello, previamente crearemos el modelo de datos Libro (libro.model.ts) y un chero mock data (mocks.ts) con un conjunto de libros de prueba. Esto lo realizaremos mediante la opción New File del menú que aparece al pulsar el botón derecho del ratón sobre la carpeta app. Luego, añadiremos el siguiente código:

    src/app/libro.model.ts export class Libro {

    id: number;

    titulo: string;

    autor: string;}

    src/app/mocks.ts import{ Libro } from’./libro.model’;

    export const LIBROS: Libro[] = [{“id”: 1,”titulo”: “El Quijote”,”autor”: “Cervantes”},

    {

    “id”: 2,”titulo”: “Hamlet”,”autor”: “Shakespea-

    re”}];

    Seguidamente realizaremos las siguientes modicaciones en el componente libroLista para que visualice esos libros: El gran libro de Angular

    175

    src/app/libro-lista/libro-lista.component.ts import{ Libro } from’../libro.model’; import { LIBROS } from ‘../mocks’; … export class LibroListaComponent implements OnInit { libros: Libro[]; … ngOnInit() {

    this.libros = LIBROS;

    }

    } src/app/libro-lista/libro-lista.component.html

    Libros: 714r5z

    • {{ libro.titulo }}


    4. Una vez creados los componentes, pasaremos a realizar la conguración del servicio Router. El primer paso será realizar la importación del servicio en “app.module.ts”: src/app/app.module.ts import { RouterModule, Routes } from ‘@angular/router’;…

    A continuación, realizaremos la conguración de rutas en el mismo chero: src/app/app.module.ts const appRoutes: Routes = [ { path: ‘libros’, component: LibroListaComponent }, { path: ‘autores’, component: AutorListaComponent }, { path: ‘’, redirectTo: ‘/libros’, pathMatch: ‘full’ }, { path: ‘**’, component: NotFoundComponent } ]; @NgModule({ declarations: […], imports: […,RouterModule.forRoot(appRoutes)], …

    176

    El gran libro de Angular

    Y, nalmente, pondremos la etiqueta router-outlet para indicar al servicio Router dónde realizar las visualizaciones de los componentes. Para ello, ponga el siguiente código en “app.component.html”: src/app/app.component.html

    Servicio Router: ejemplos de uso 71666c



    5. La primera parte del ejercicio termina aquí. Desde el navegador puede realizar las pruebas para validar el código. Para el URL “localhost:4200/”, será redireccionado a “localhost:4200/libros”, donde visualizará la vista de libros, para “localhost:4200/autores”, visualizará la vista de autores, y para cualquier otra ruta, visualizará la vista de “Not Found”.

    El gran libro de Angular

    177

    045

    Routing: RouterLinks

    Llegados a este punto, nuestro servicio Router ya estaría gestionando correctamente los cambios de direcciones URL de la barra de direcciones del navegador. Sin embargo, la navegación en una aplicación web principalmente se realiza desde la misma aplicación haciendo clics sobre enlaces a otras vistas.

    Importante Las directivas RouterLink nos permiten crear enlaces a partes especícas de nuestras aplicaciones.

    En HTML, estos enlaces se realizan mediante la etiqueta y su atributo “href”, que sería donde pondríamos la dirección URL. Sin embargo, al haber creado un servicio Router, nos interesa que todo el control de rutas lo realice el mismo servicio. Por eso Angular dispone de las directivas RouterLink. Si en las etiquetas sustituimos los atributos “href” por directivas RouterLink, conseguiremos que el servicio Router tome el control de todos estos elementos. Los path congurados en RouterLink pueden ser estáticos:

    o dinámicos, donde usamos una cadena con literales y variables para formar el path dinámicamente:

    En el primero de los ejemplos anteriores, se hace uso de la directiva RouterLinkActive. Esta directiva sirve para aplicar una clase CSS al elemento cuando la ruta del link esté activa. De esta manera podremos distinguir qué enlace, de todos los visibles en la aplicación, es el que está activo. Por otra parte, el primer segmento del path puede venir precedido por “/”, “../” o “./”. Esto indica a Angular en qué parte de árbol de rutas realizar el link del path. Si, por el URL activo, el que aparece en la barra de direcciones, fuese “localhost:4200/libros” y quisiéramos desplazarnos a “localhost:4200/libros/comics”, en routeLink podríamos poner el path “/libros/comics” o “./comics” o “comics”.

    178

    El gran libro de Angular

    Continuando la aplicación que habíamos empezado en el ejercicio anterior, añadiremos dos enlaces en la página principal de la aplicación usando RouterLink. Uno nos llevará a la vista de los libros y el otro a la de los autores. 1. Desde la línea de comandos nos situaremos en ej100_angular/044_routing, y ejecutaremos la aplicación con ng serve. A continuación, abriremos el proyecto con Atom. 2. A continuación, editaremos el template del componente principal de la aplicación y añadiremos los dos enlaces usando RouterLink. Todas las clases CSS usadas en el siguiente código forman parte de las hojas de estilo de Bootstrap. src/app/app.component.html …



    Desde el navegador puede realizar pruebas de los enlaces. Al hacer clic sobre uno u otro link verá cómo cambia la vista y la dirección URL de la barra de direcciones del navegador.

    El gran libro de Angular

    179

    3. El siguiente paso será usar la directiva RouterLinkActive para añadir una clase CSS al enlace cuando este haya sido seleccionado. De esta manera, en cualquier momento podremos ver a qué enlace pertenece la vista que tenemos en pantalla. 4. Para ello, primero crearemos la clase CSS active-link en app.component. css, o sea, en la hoja de estilos asociada al componente principal de la aplicación. Lo único que hará esta clase CSS será dejar las letras en color naranja. src/app/app.component.css .active-link { color: orange; }

    Finalmente añadiremos el uso de RouterLinkActive en los enlaces creados: src/app/app.component.html …



    180

    El gran libro de Angular

    5. Desde el navegador podrá comprobar cómo cambia el color del enlace a naranja cuando lo selecciona.

    El gran libro de Angular

    181

    046

    Routing: Rutas con parámetros y ActivatedRoute

    En una conguración de rutas podríamos tener rutas con parámetros, es decir, rutas con una parte ja y otra variable. Por ejemplo: const appRoutes: Routes = [ { path: ‘libro/:id’, component: ,

    ...,

    Con esta conguración, el servicio Router seleccionaría esta primera línea de conguración para direcciones URL como: “/libro/2, “/libro/aa” o “/libro/4vd”, pero no para direcciones como “libro/2/opiniones” o “libro/3/productos-relacionados”. Luego, el componente seleccionado accedería al valor del parámetro “:id” para realizar las acciones que convenga.

    Importante Utilice “:” para indicar los parámetros de las rutas que congure. Acceda a ActivatedRoute para consultar los valores de esos parámetros y otra información relacionada con la ruta activa.

    Para obtener el valor de los parámetros que pueden venir por URL, el componente utiliza el objeto ActivatedRoute. ActivatedRoute contiene información de la ruta asociada al componente que actualmente tengamos cargado en la etiqueta “router-outlet”, por lo tanto, información de la actual ruta activa. Si desea más información de ActivatedRoute consulte https://angular.io/api/router/ ActivatedRoute. Para continuar con la aplicación que habíamos empezado en los ejercicios anteriores, vamos a crear el código necesario para que se puedan seleccionar libros de la lista de libros y ver su detalle. El detalle lo gestionará un nuevo componente, LibroDetalle, al que asociaremos a una nueva ruta URL: “libros/:id”. El parámetro “:id” indicará el libro del cual deseamos ver su detalle. 1. Desde línea de comandos nos situaremos en ej100_angular/044_ routing, y ejecutaremos la aplicación con ng serve. A continuación, abriremos el proyecto con Atom. 2. Sin salir de línea de comandos, crearemos el componente LibroDetalle. C:\Ej100_angular\044_routing>ng generate component libroDetalle

    182

    El gran libro de Angular

    3. Seguidamente, en la conguración de rutas, añadiremos la nueva ruta y componente: src/app/app.module.ts const appRoutes: Routes = [ { path: ‘libros’, component: LibroListaComponent }, { path: ‘libros/:id’, component: LibroDetalleComponent }, …

    En el componente LibroDetalle añadiremos el código para primero obtener el identicador del libro (parámetro “:id” del URL) y luego para leer el detalle de ese libro. Para obtener los parámetros de la ruta, ActivateRoute nos proporciona el observable paramMap. Para obtenerlos, simplemente nos suscribiremos al observable a la espera de recibirlos. De esta manera recibiremos el identicador de libro. En el capítulo “052 Servicios: Gestión asíncrona con observables” veremos con más detalle los observables, pero, en lo que respecta a este ejercicio, no es necesario que profundicemos más en el tema.

    El gran libro de Angular

    183

    src/app/libro-detalle/libro-detalle.component.ts import { Component, OnInit } from ‘@angular/core’; import { ActivatedRoute, ParamMap } from ‘@angular/router’; import{ Libro } from’../libro.model’; import { LIBROS } from ‘../mocks’;

    … export class LibroDetalleComponent implements OnInit { libro: Libro;

    constructor( private route: ActivatedRoute) { }

    ngOnInit() { this.route.paramMap .subscribe((params: ParamMap) => { let id = +params.get(‘id’); this.libro =

    LIBROS.nd(item => item.id === id);

    }); } }

    En el template del componente añadiremos el código para visualizar el detalle del libro. src/app/libro-detalle/libro-detalle.component.html

    Libro detalle: 6l1616

    Identicador
    {{ libro.id }}
    Titulo
    {{ libro.titulo }}
    Autor
    {{ libro.autor }}


    4. Y, nalmente, añadiremos un enlace o link al componente LibroDetalle para cada uno de los libros del componente LibroLista: src/app/libro-lista/libro-lista.component.html

    184

    El gran libro de Angular

  • {{ libro.titulo }}


  • Desde el navegador puede realizar pruebas de los diferentes enlaces creados.

    El gran libro de Angular

    185

    047

    Routing: child routes

    Angular nos permite crear árboles de conguraciones de rutas mediante child routes: { path: ‘actor/:id’, component: LibroDetalleComponent, children: [ { path: ‘biograa’, component: ActorBiograaComponent }, { path: ‘lmograa’, component: ActorFilmograaComponent } ] },…

    Los path de conguraciones hijos son relativos a los de las conguraciones padre. Por ejemplo, “/actor/:id/biograa” o “/actor/:id/lmograa” en el código anterior. Por otra parte, en el template de todo componente padre siempre habrá que añadir la etiqueta router-outlet. Allí será donde el servicio Router visualice los componentes hijos. Al usar child routes, podemos tener varias rutas activas (ActivatedRoute) al mismo tiempo durante la navegación. En esta situación, es probable que desde un componente cualquiera necesitemos acceder a una ruta determinada del árbol de rutas activas para, por ejemplo, leer parámetros. Angular nos proporciona dos maneras de acceder al árbol de rutas activas. La primera consiste en partir de una ruta activa (ActivatedRoute) cualquiera, y usar sus propiedades parent y children para desplazarnos por el árbol. Y la segunda consiste en usar la propiedad RouterState. Esta propiedad nos permite obtener el árbol de rutas activas en cualquier momento y lugar de la aplicación.

    Importante Con child routes podemos crear árboles de rutas que faciliten la gestión de rutas de nuestras aplicaciones.

    Continuando la aplicación que habíamos empezado en los ejercicios anteriores, vamos a añadir dos child routes, “opiniones” y “imágenes”, a la ruta “libros/:id”. Las dos rutas estarán asociadas a dos nuevos componentes, “LibroOpiniones” y “LibroImagenes”, respectivamente. No entraremos a desarrollar estos dos componentes, 186

    El gran libro de Angular

    pero sí que les añadiremos el código necesario para obtener el identicador de libro del URL. 1. Desde línea de comandos nos situaremos en ej100_angular/044_routing, y ejecutaremos la aplicación con ng serve. A continuación, abriremos el proyecto con Atom. 2. Sin salir de la línea de comandos, crearemos el componente LibroOpiniones y LibroImagenes. C:\Ej100_angular\044_routing>ng generate component libroOpiniones C:\Ej100_angular\044_routing>ng generate component libroImagenes

    3. Seguidamente, en la conguración de rutas, añadiremos las nuevas child routes: src/app/app.module.ts … { path: ‘libros/:id’, component: LibroDetalleComponent, children: [ { path: ‘imagenes’, component: LibroImagenesComponent }, { path: ‘opiniones’, component: LibroOpinionesComponent }, { path: ‘’, redirectTo: ‘imagenes’, pathMatch: ‘full’ }, { path: ‘**’, component: NotFoundComponent } ]}, …

    En el template del componente padre, LibroDetalle, añadiremos dos enlaces a estas nuevas rutas y la etiqueta router-outlet para visualizar sus componentes asociados: El gran libro de Angular

    187

    src/app/libro-detalle/libro-detalle.component.html …

    src/app/libro-detalle/libro-detalle.component.css .active-link { color: orange;}

    4. A continuación, añadiremos el código necesario en LibroImagenes para cargar el identicador de libro que serviría al componente para cargar las imágenes relacionadas. Para ello, haremos uso de ActivatedRoute primero para acceder al ActivatedRoute parent, y luego para obtener el valor del parámetro. src/app/libro-imagenes/libro-imagenes.component.ts import { ActivatedRoute, ParamMap } from ‘@angular/router’; … export class LibroImagenesComponent implements OnInit { idLibro: number;

    constructor(

    private route: ActivatedRoute

    ngOnInit() { this.route.parent.paramMap .subscribe((params: ParamMap) => { this.idLibro = +params.get(‘id’); }); } }

    188

    El gran libro de Angular

    ) { }

    src/app/libro-imagenes/libro-imagenes.component.html

    (Imagenes del libro con identicador: {{idLibro}})



    Desde el navegador puede realizar pruebas de los diferentes enlaces creados.

    El gran libro de Angular

    189

    048

    Inyección de dependencias (DI)

    La inyección de dependencias es un patrón de diseño muy usado en Angular. Se basa en que las clases no crean sus dependencias por sí mismas, sino que las reciben de fuentes extremas. Analicémoselo con un ejemplo. Imaginen el siguiente código. Se trata de una clase llamada Musico que utiliza métodos de un objeto de tipo “Instrumento”.

    import { Instrumento }

    Importante La inyección de dependencias es un patrón de diseño que nos permite aislar las dependencias de nuestras clases consiguiendo unas clases más fuertes, exibles y probables.

    from ‘./instrumento’;

    export class Musico { public instrumento: Instrumento; constructor() { this.instrumento = new Instrumento(); } tocar(): string { }

    190

    El gran libro de Angular

    return this.instrumento.tocar();

    }

    Esta clase Musico presenta los siguientes problemas: Frágil: si por ejemplo se realizaran cambios sobre el constructor de “Instrumento” añadiendo un parámetro obligatorio, la clase Musico fallaría a no ser que se adaptara su código. Inexible: no es posible asignarle otro tipo de “Instrumento”, ni tampoco es posible que comparta un mismo “Instrumento” a la vez con otro “Musico”. Siempre será necesario adaptar su código. Difícil para realizar test: los test sobre “Musico” son peligrosos ya que estamos a merced de las dependencias escondidas que no vemos: no sabemos qué puede suponer crear un objeto de tipo “Instrumento” en un entorno de pruebas…







    Aplicando la inyección de dependencias, la clase Musico quedaría de la siguiente manera: import { Instrumento }

    from ‘./instrumento’;

    export class Musico {

    constructor(public instrumento: Instrumento) {

    tocar(): string {

    }

    return this.instrumento.tocar();

    }

    }

    Y el consumidor de la clase realizaría lo siguiente:

    import { Musico } from ‘./musico’; import { Instrumento }

    from ‘./instrumento’;

    ... let musico = new Musico(new Instrumento()); console.log(musico.tocar());

    Las deniciones de las dependencias ahora están en el constructor. La clase Musico ya no crea el objeto “Instrumento”, ahora lo consume. De esta manera, quien hace uso de Musico es quien tiene todo el control sobre sus dependencias. Por tanto, podemos realizar acciones como las que comentábamos antes sin que el código de la El gran libro de Angular

    191

    clase Musico se vea afectado. Por ejemplo, podríamos crear una nueva versión de la clase Instrumento añadiendo un parámetro obligatorio en su constructor:

    export class Instrumento2 {

    constructor(public nombre: string) {}

    tocar(): string {…} }

    y probarla en nuestra clase Musico sin realizar más modicaciones: //let musico = new Musico(new Instrumento()); let nombre = “piano”; let musico = new Musico(new Instrumento2(nombre));

    A pesar de las ventajas comentadas, ahora el consumidor se ve obligado a crear todas las dependencias de la clase Musico cuando antes no tenía que hacerlo. Para solucionar este y otros temas relacionados, existen los frameworks de inyección de dependencias. Angular dispone de su propio framework al respecto. Entre otras cosas, nos permitirá que mediante el uso de inyectores (injectors) y proveedores (providers) configuremos el sistema para que el consumidor simplemente tenga que realizar lo siguiente para crear un objeto Musico:

    let musico = injector.get(Musico); console.log(musico.tocar());

    192

    El gran libro de Angular

    Tanto el consumidor como la clase Musico solamente preguntan por lo que necesitan y el inyector lo entrega. En los siguientes capítulos describiremos en detalle del framework de inyección de dependencias de Angular.

    El gran libro de Angular

    193

    049

    Servicios: Denición y uso mediante la inyección de dependencias (parte I)

    Un servicio Angular es una clase que encapsula algún tipo de funcionalidad común entre los diferentes componentes de la aplicación, como podría ser, por ejemplo, el a datos. La extracción de funcionalidades comunes de los componentes para crear servicios supone toda una serie de ventajas: •





    Importante El framework de inyección de dependencias de Angular permite aislar las dependencias de las clases, pero también permite aislarlas del que las consume.

    Evitamos la repetición innecesaria de código en los componentes, por lo que su código acaba siendo más ligero y centrado en el soporte a la vista. Podemos crear servicios mock (de prueba) que faciliten el análisis de los componentes que los usan. Mejoramos el control y mantenimiento de esas funcionalidades comunes.

    Vamos a ver cómo sería el formato estándar de cualquier servicio a través de un ejemplo: import { Injectable } from ‘@angular/core’;

    @Injectable() export class LoggerService { log(message: string) {

    console.log(message);

    }

    constructor() { } }

    Como vemos no es más que una clase estándar donde se le ha añadido el decorador @Injectable(). De momento dejaremos el análisis de este decorador para más adelante. Los servicios son suministrados a los componentes mediante el patrón de diseño inyección de dependencias que hemos visto en el capítulo anterior. Angular incorpora un framework al respecto. Básicamente, este framework nos facilita la gestión de dependencias mediante inyectores (injectors) y proveedores (pro194

    El gran libro de Angular

    viders). Estos elementos los podríamos denir de la siguiente manera: •

    •

    Un inyector mantiene una colección de servicios previamente instanciados. Si se requiere un servicio aun no instanciado, el inyector crea una instancia mediante un proveedor y lo agrega a la colección. Un proveedor es algo que puede crear o devolver una instancia de servicio. Normalmente es la clase del servicio en sí. Para que el inyector pueda hacer uso de los proveedores, estos deben estar registrados. Estos registros pueden hacerse a nivel de módulo o componente, dependiendo de la disponibilidad que se le quiera dar al servicio.

    En el diagrama general de la arquitectura Angular puede observar dónde se situaría el inyector y su colección de servicios previamente instanciados.

    A partir de aquí, vamos a ver cómo utilizaríamos todas estas herramientas para que los componentes pudieran usar el servicio de ejemplo que hemos creado antes (LoggerService). Durante el proceso de inicialización de la aplicación, Angular ya crea un inyector de forma automática. Lo que tenemos que hacer nosotros es registrar el proveedor de nuestro servicio para que el inyector pueda usarlo. Dado el tipo de servicio del ejemplo, lo registraremos en ngModule para que pueda usarse en toda la aplicación. Esto lo haríamos de la siguiente manera: @NgModule({ ..., providers: [LoggerService], ...}) export class AppModule { }

    En este caso hemos realizado el registro del proveedor de la forma más básica, sin embargo, hay que tener en cuenta que Angular nos ofrece muchas opciones al respecto. Veamos algunos ejemplos: El gran libro de Angular

    195

    •

    providers: [LoggerService]…

    o … [{

    provide: LoggerService, useClass:

    LoggerService }]

    Es el método de registro que hemos visto antes. •

    [{ provide: LoggerService, useClass: LoggerService2 }]

    Le decimos al inyector que instancie otra versión del servicio. Finalmente haríamos la inyección del servicio en el componente que necesitara usarlo: @Component({...}) export class EjemploComponent implements OnInit { constructor(private loggerService: LoggerService){ ngOnInit() {

    this.loggerService.log(“hola”);

    }

    }

    }

    La combinación del tipo de parámetro del constructor (LoggerService), el decorador @Component y la información de los proveedores registrados, indican al inyector de Angular que inyecte una instancia de “LoggerService” cuando se cree un nuevo “EjemploComponent”. Por lo tanto, como consumidores de “EjemploComponent”, el framework también nos aísla de sus dependencias. Desde el punto de vista de un inyector, las dependencias son “singletons”. Esto signica que, por defecto, el inyector creará una única instancia de cada clase, la cual será compartida por los distintos componentes. Por último, analizaremos un poco el decorador @Injectable() que ponemos en las clases de nuestros servicios. El decorador @Injectable() marca una clase como disponible para un inyector para poder instanciarla. Sin este decorador, el inyector informaría de un error si intentara instanciarla. Los inyectores también son responsables de instanciar componentes; sin embargo, no hace falta poner @Injectable() porque @Component, y otros decoradores como @Directive o @Pipe, son subtipos de @Injectable(). En el siguiente ejercicio pondremos en práctica todos estos conceptos creando y usando un servicio.

    196

    El gran libro de Angular

    050

    Servicios: Denición y uso mediante inyección de dependencias (parte II)

    En este ejercicio pondremos en práctica los servicios y la inyección de dependencias que hemos visto en los anteriores capítulos. Aplicaremos todos estos conceptos en una nueva aplicación extraída en parte de la aplicación de gestión de Libros que habíamos desarrollado en los ejercicios dedicados al “Router”.

    Importante Los servicios nos permiten extraer funcionalidades comunes de nuestros componentes dejándolos más centrados en el soporte a la vista.

    1. Nos ubicaremos en ej100_angular, y crearemos el proyecto tecleando ng new servicios. Seguidamente lo renombraremos para que haga referencia a nuestro número de ejercicio ejecutando rename servicios 050_servicios, y nalmente pondremos en marcha la aplicación ejecutando ng serve desde dentro la carpeta 050_servicios. A continuación, abriremos el proyecto con el editor Atom.

    2. Seguidamente añadiremos los links de Bootstrap (https://v4-alpha. getbootstrap.com) en index.html para poder hacer uso de sus hojas de estilo. Consulte “087 Bootstrap: Introducción” para obtener más información. 3. Desde la línea de comandos, crearemos el componente LibroLista. C:\Ej100_angular\050_servicios>ng generate component libroLista

    El gran libro de Angular

    197

    Añadiremos su código y crearemos los cheros libro.model.ts y mocks.ts que necesita: src/app/libro-lista/libro-lista.component.ts import{ Libro } from’../libro.model’; import { LIBROS } from ‘../mocks’; … export class LibroListaComponent implements OnInit { libros: Libro[]; ngOnInit() {

    this.libros = LIBROS;

    }

    } src/app/libro-lista/libro-lista.component.html
    • {{ libro.titulo }}
    src/app/libro.model.ts export class Libro {

    id: number;

    titulo: string;

    autor: string;}

    src/app/mocks.ts import{ Libro } from’./libro.model’; export const LIBROS: Libro[] = [{“id”: 1,”titulo”: “El Quijote”,”autor”: “Cervantes”},

    {

    “id”: 2,”titulo”: “Hamlet”,”au-

    tor”: “Shakespeare”}];

    Seguidamente añadiremos LibroLista al componente principal para poder visualizarlo en el navegador: src/app/app.component.html


    4. El componente LibroLista obtiene los libros por sí solo. Esta funcionalidad previsiblemente será usada por otros componentes, por lo que lo mejor será dejarlo como servicio. Vamos a crearlo. También crearemos un segundo servicio para grabar log que será usado por el primero:

    198

    El gran libro de Angular

    C:\Ej100_angular\050_servicios>ng generate service libro C:\Ej100_angular\050_servicios>ng generate service logger

    Para poder hacer uso de los servicios, el primer paso será registrar su proveedor. En este caso, lo haremos a nivel de módulo para que todos sus componentes puedan usarlos: src/app/app.module.ts … import { LoggerService } import { LibroService }

    from ‘./logger.service’; from ‘./libro.service’;

    @NgModule({…, providers: [LoggerService,LibroService],…}) export class AppModule { }

    A continuación, añadiremos su código. Además, para el servicio Libro, también le inyectaremos el servicio Logger, ya que lo usará: src/app/logger.service.ts … @Injectable() export class LoggerService { constructor() { } log(message: string) { console.log(“(“ + new Date().toLocaleTimeString() + “) “ + message);} }

    El gran libro de Angular

    199

    src/app/libro.service.ts … @Injectable() export class LibroService { constructor(private loggerService: LoggerService) { } getLibros() { this.loggerService.log(“Llamada realizada sobre LibroService. getLibros”); return LIBROS;} }

    Finalmente modicaremos nuestro componente para que use el servicio Libro: src/app/libro-lista/libro-lista.component.ts … @Component({…}) export class LibroListaComponent implements OnInit { libros: Libro[]; constructor(private libroService: LibroService){ ngOnInit() {

    }

    this.libros = this.libroService.getLibros();

    }

    }

    5. Desde el navegador podrá comprobar su funcionamiento. Recuerde que para visualizar log debe habilitar la opción “Más herramienta/Herramientas para desarrolladores” de Google Chrome.

    200

    El gran libro de Angular

    El gran libro de Angular

    201

    051

    Servicios: Gestión asíncrona con promesas

    Los dos servicios que hemos creado en el ejercicio anterior, LoggerService y LibroService, devuelven respuestas inmediatas, por lo que se han gestionado de forma síncrona. Sin embargo, muchas veces tendremos servicios que realizarán llamadas a servidores remotos cuyas respuestas no sabemos cuánto tiempo tardarán en llegar. Esos servicios no pueden gestionarse de la misma forma, ya que produciríamos bloqueos inaceptables en la aplicación. Esos servicios hay que gestionarlos de forma asíncrona. De esta manera, el podrá seguir trabajando mientras se ejecutan los servicios.

    Importante Para mantener un buen nivel de uidez en nuestras aplicaciones, siempre deberíamos trabajar con servicios asíncronos. Las promesas son una buena herramienta para su implementación.

    Las promesas es una de las herramientas que nos permite la programación asíncrona. Tal como su nombre indica, una promesa la podríamos denir como un valor que se espera en un tiempo futuro no denido después de ejecutar, de forma asíncrona, una operación. Su sintaxis sería la siguiente: new Promise( /* ejecutor */ function(resolver, rechazar) { ... } );

    La función ejecutor empieza a ejecutarse de forma asíncrona justo en el momento en el que se crea la promesa. La función ejecutor, al terminar, deberá llamar a la función resolver para resolver la promesa con el valor obtenido, o llamar a la función rechazar para rechazarla con el error producido. Finalmente, mediante los métodos “then” y “catch” de la promesa, gestionaremos esa resolución y rechazo, respectivamente. Vea en el ejemplo cómo gestionamos la promesa devuelta por el método get.

    202

    El gran libro de Angular

    Una llamada al método “then” de una promesa devuelve otra promesa a la que también podemos llamar a su método “then”, y así sucesivamente. Esto nos permitirá encadenar promesas. Vamos a ver unos ejemplos que realizaremos sobre la aplicación que habíamos creado en el anterior ejercicio. Modicaremos “getLibros” de “LibroService” para que devuelva una promesa de los Libros, y le añadiremos un retraso de 5 segundos para simular una llamada a un servidor remoto. 1. Desde línea de comandos nos situaremos en ej100_angular/050_ servicios, y ejecutaremos la aplicación con ng serve. A continuación, abriremos el proyecto con el editor Atom. 2. Editaremos el código del servicio “LibroService” y realizamos las modicaciones comentadas: src/app/libro.service.ts … @Injectable() export class LibroService { constructor(private loggerService: LoggerService) { } getLibros(): Promise { return new Promise ( (resolve, reject) => { this.loggerService.log(“Inicio ejecutor (Promise de LibroService. getLibros())”); setTimeout(() => { this.loggerService.log(“Fin ejecutor (Promise de LibroService. getLibros())”); resolve(LIBROS); }, 5000); });} }

    Finalmente modicaremos el componente para que gestione la promesa:

    El gran libro de Angular

    203

    src/app/libro-lista/libro-lista.component.ts … @Component({…}) export class LibroListaComponent implements OnInit { libros: Libro[]; constructor(private libroService: LibroService){

    }

    ngOnInit() { this.libroService.getLibros().then(libros => this.libros = libros); } }

    Desde el navegador podremos comprobar su funcionamiento. Recuerde que para ver los “logs” debe activar la opción “Más herramientas/Herramientas para desarrolladores” de Google Chrome.

    3. Para probar el encadenamiento de promesas, realizaremos los siguientes cambios: src/app/libro-lista/libro-lista.component.ts @Component({…}) export class LibroListaComponent implements OnInit { libros: Libro[]; constructor(private libroService: LibroService, private loggerService: LoggerService){

    }

    ngOnInit() { this.libroService.getLibros() .then( libros => { this.loggerService.log(“Ejecucion del 1º then”); return libros;})

    204

    El gran libro de Angular

    .then( libros => { this.loggerService.log(“Ejecucion del 2º then”); return new Promise ((resolve, reject) => { // (*) this.loggerService.log(“Inicio ejecutor (Promise del 2º then)”); setTimeout(() => { this.loggerService.log(“Fin ejecutor (Promise del 2º then)”); resolve(libros); }, 5000); });}) .then( libros => { this.loggerService.log(“Ejecucion del 3º then”); this.libros = libros;}); } }

    Desde el navegador y su consola podremos comprobar la secuencia de ejecuciones.

    El gran libro de Angular

    205

    052

    Servicios: Gestión asíncrona con observables (Librería RxJs) (parte I)

    Los observables de las librerías RxJS (reactive extensions for JavaScript) son otra herramienta que nos permitirá programación asíncrona. Veamos cuáles son las principales diferencias respecto a las promesas que veíamos en el anterior ejercicio: Una promesa siempre devolverá un valor o un error, mientras que un observable puede emitir múltiples valores en el tiempo. Por este motivo, a veces se le dene como un ujo de datos o “stream”. Una promesa no puede cancelarse, en cambio un observable sí. Si el valor esperado por una promesa (p. ej., el resultado de una llamada a un servicio) ya no es necesario, no hay manera de cancelar esa promesa. Siempre acabará llamándose a su “callback” de éxito o rechazo. En un observable no ocurre lo mismo, ya que siempre podemos anularlo cancelando la suscripción previa que se habría realizado.





    Importante Los observables proporcionan y amplían las características de las promesas. Permiten manejar 0, 1 o N eventos, y pueden cancelarse.

    La sintaxis de una observable sería la siguiente: vObs = new Observable( /* ejecutor */ observer => { ... } /*o lo que es lo mismo: function(observer) { ... } */ ); vObsSubs = vObs.subscribe( value => ..., error => ..., () => ... );

    206

    El gran libro de Angular

    La función ejecutor empieza a ejecutarse de forma asíncrona cuando un observador (u “observer”) realiza una suscripción en el observable. Esta suscripción se traduce en una ejecución al método “subscribe(observer)” del observable. En el caso que se realizara otra suscripción al mismo observable, se pondría en marcha otro hilo de ejecución asíncrona distinta. Una vez realizada la suscripción, el observador (u “observer”) recibirá cualquier dato emitido por el observable. En la suscripción al observable, es posible pasar una instancia del objeto observador que previamente haya creado, o puede pasar directamente las tres funciones de retorno o “callback” que lo denen: la primera es ejecutada al recibir nuevos valores, la segunda al recibir un error, y la última al recibir la noticación de nalización. Toda esa información será emitida por el observable usando los siguientes métodos del observador: next(), error() o complete(). Para cancelar una suscripción ejecutaremos “unsuscribe()” sobre la suscripción. Esta cancelación siempre debe realizarse en suscripciones de observables que emitan valores de forma indenida sin terminar nunca. En caso contrario, podrían producirse memory leaks (problemas de memoria). Los observables aquí explicados son los llamados cold observables, no emiten valores hasta que un observador se suscribe a ellos. Sin embargo, también existen los hot observables, que emiten valores aunque no haya suscriptores. Para más información consulte: http://reactivex.io/rxjs/manual/overview.html. Continuando la aplicación de los anteriores ejercicios, vamos a crear un nuevo servicio “LibroObservableService” con un método “getLibros” que devuelva un observable. El observable no devolverá todos los libros de golpe como hacía el servicio “LibroService”, sino que irá devolviendo cadenas de libros cada segundo y medio añadiendo un nuevo libro en cada envío. Al nal, enviará la noticación de nalización. 1. Desde línea de comandos nos situaremos en ej100_angular/050_ servicios, y ejecutaremos la aplicación con ng serve. A continuación, abriremos el proyecto con el editor Atom. 2. Desde la línea de comandos, crearemos el servicio LibroObservableService: C:\Ej100_angular\050_servicios>ng generate service libroObservable

    Y le añadiremos el siguiente código:

    El gran libro de Angular

    207

    src/app/libro-observable.service.ts @Injectable() export class LibroObservableService { libros: Libro[]; constructor() { } getLibros(): Observable { return new Observable ( observer => { let libros: Libro[] = []; observer.next([]); LIBROS.forEach((libro, index) => { setTimeout(() => { libros.push(libro); observer.next(libros); }, (index + 1) * 1500); }); setTimeout(() => {observer.complete();}, (LIBROS.length + 1) * 1500); }); } }

    A continuación registraremos el proveedor del servicio en app.module.ts, y nalmente modicaremos nuestro componente libro-lista.component. ts para que lo use: src/app/libro-lista/libro-lista.component.ts ngOnInit() { this.observableSubs= this.libroObservableService.getLibros() .subscribe( libros => this.libros = libros, error => console.log(error), () => console.log(“this.libroObservableService.getLibros() FINALIZADO”) ); } ngOnDestroy(){ if (this.observableSubs) this.observableSubs.unsubscribe();

    }

    }

    208

    El gran libro de Angular

    3. Desde el navegador y su consola podremos comprobar la secuencia de elementos devueltos por el observable cada segundo y medio.

    El gran libro de Angular

    209

    053

    Servicios: Gestión asíncrona con observables (Librería RxJs) (parte II)

    Las librerías RxJS (reactive extensions for JavaScript) incluyen toda una serie de operadores que, combinados con los observables, pueden llegar a ser muy útiles. El abanico de operadores es muy amplio, por lo que para facilitar su comprensión se suelen clasicar por categorías. En este capítulo veremos algunas de las categorías y operadores más usados. Si desea más información, le recomendamos que consulte la documentación ocial: http://reactivex.io/documentation/operators.html.

    Importante Gracias a los observables y a sus operadores, la librería RxJs (reactive extension for JavaScript) es una de las herramientas más importantes que hay en el mercado a la hora de trabajar con ujos de datos asíncronos.

    Para cada uno de los operadores comentados hay un pequeño ejemplo. Si lo desea, puede implementarlos en un nuevo proyecto para ponerlos a prueba. Recuerde que para crear el proyecto seguiremos estos pasos: 1. Nos ubicaremos en ej100_angular, y crearemos el proyecto tecleando ng new rxjs. Seguidamente lo renombraremos para que haga referencia a nuestro número de ejercicio ejecutando rename rxjs 053_rxjs, y nalmente pondremos en marcha la aplicación ejecutando ng serve desde la carpeta 053_rxjs. A continuación, abriremos el proyecto con el editor Atom.

    210

    El gran libro de Angular

    2. Los ejemplos los implementaremos en app.component.ts. Para vericarlos, sobre los observables realizaremos suscripciones que graben en log los valores obtenidos. Recuerde visualizar los log activando: “Más Herramientas/ Herramientas para desarrolladores” del menú del Google Chrome. Operadores de creación El operador create crea un observable que ejecutará la función especíca cuando un observador se suscriba. vObs = Observable.create( /* ejecutor */ observer => { ... });

    En el anterior capítulo lo habíamos visto hacer de otra forma (“vObs = new Observable (..)”), pero el resultado nal es el mismo. En los dos casos obtenemos un observable con una función congurada. El operador interval crea un observable que emite números secuenciales (0,1,...) cada cierto intervalo de tiempo según lo que le hayamos indicado por parámetro. Vea el siguiente ejemplo: var source = Observable.interval(1000); //Emite secuencia 0, 1, 2, ... cada 1 segundo

    El observador que se haya suscrito recibirá un número secuencial cada segundo. Mirar imagen.

    El gran libro de Angular

    211

    El operador of crea un observable que emite los valores que se le hayan pasado por parámetro y naliza emitiendo la noticación de nalización. var source = Observable.of(‘a’,’b’,’c’); //Emite secuencia ‘a’, ‘b’ y ‘c’

    El operador from permite crear un observable a partir de distintos objetos y tipos de datos. Las posibilidades son muy amplias. A continuación, puede ver un ejemplo donde partimos de una promesa que se resuelve en dos segundos devolviendo una cadena de caracteres, y otro donde partimos de un array: var source = Observable.from( new Promise<string>( (resolve, reject) => { setTimeout(() => { resolve(“Valor resuelto por la Promise.”); }, 2000); }) ); var source = Observable.from([{nombre: ‘Miguel’, edad: 30}, {nombre: ‘Juan’, edad: 35}]);

    Operadores de transformación El operador map transforma los valores emitidos por un observable aplicando una función, y devuelve un observable que emite los valores transformados. var source = Observable.interval(1000).map(x => 2 * x); //Emite secuencia 0, 2, 4, ...

    Operadores de combinación El operador merge nos permite combinar varios observables en uno solo fusionando sus emisiones: var source1 = Observable.interval(1000); var source2 = Observable.interval(1000).map(x => 10 * x); var source3 = source1.merge(source2); //Emite secuencia 0, 0, 1, 10, 2, 20,...

    En este ejemplo, el observador que se haya suscrito a “source3” recibirá 0 y 0, el primer segundo, 1 y 10, el siguiente segundo, … y así sucesivamente. . El operador concat es similar a merge, pero en este caso el observable resultado de la fusión emite los valores de los distintos observables de forma ordenada: primero los del primer observable, luego del segundo, etc. var source1 = Observable.of(‘a’,’b’,’c’);

    212

    El gran libro de Angular

    var source2 = Observable.of(‘d’,’e’,’f’); var source3 = source1.concat(source2); //Emite secuencia a, b, c, d, e, f

    Operadores de utilidad El operador do nos permite realizar una acción para cada uno de los valores emitidos por un observable, pero sin posibilidad de modicarlos. El operador devuelve un observable idéntico al de entrada. var source = Observable.of(‘a’,’b’,’c’).do(x => console.log(x)); //Emite secuencia ‘a’, ‘b’ y ‘c’, y muestra estos valores por log

    El gran libro de Angular

    213

    054

    HttpClient: Introducción e instalación

    Una aplicación web puede dividirse en dos grandes bloques: Front-end y Back-end. El Front-end es la parte que se muestra a través del navegador web, o sea, la parte que se encarga de interactuar con el para recoger datos e información. El Back-end, por su parte, se ejecuta en un servidor y recoge a través de una API de servicios toda esa información para gestionarla (guardarla en una base de datos, realizar comprobaciones, etc.).

    Importante HttpClient es un servicio con métodos para realizar peticiones HTTP en aplicaciones Angular.

    En la mayoría de casos, la comunicación entre aplicaciones Front-end y servicios Back-end se realiza mediante el protocolo HTTP. Para realizar este tipo de comunicación, las aplicaciones se apoyan en API como la interfaz XMLHttpRequest y la API fetch(), que son soportadas por la mayoría de navegadores web y permiten al Front-end realizar peticiones HTTP. Angular, por su parte, nos ofrece el servicio HttpClient. HttpClient es un servicio que proporciona una API simplicada, construida sobre la interfaz XMLHttpRequest, para realizar peticiones HTTP y procesar sus respuestas. En este sentido, el servicio ofrece toda una serie de métodos para realizar los distintos tipos de peticiones HTTP que existen: • • • •

    214

    get post put delete

    El gran libro de Angular

    • • •

    patch head jsonp

    El servicio también aporta otros benecios muy interesantes como son el soporte a la realización de test, soporte a la intercepción de peticiones y respuesta, una mejor gestión de errores, etc. HttpClient forma parte del módulo HttpClientModule del paquete @angular/ common/http que tendremos que incluir en nuestra aplicación Angular. Hay que tener en cuenta que HttpClient está disponible en Angular 4.3.X y versiones posteriores. Para versiones anteriores existía un servicio parecido que se llamaba simplemente HTTP. Una vez realizada la introducción empezaremos nuestro ejercicio. En esta primera parte únicamente crearemos una aplicación con un único componente que habilitaremos para que pueda hacer uso del servicio HttpClient. En los siguientes ejercicios ya le añadiremos nuevas funcionalidades. 1. Nos ubicaremos en ej100_angular, y crearemos el proyecto tecleando ng new http. Seguidamente lo renombraremos para que haga referencia a nuestro número de ejercicio ejecutando rename http 054_http, y nalmente pondremos en marcha la aplicación ejecutando ng serve desde dentro la carpeta 054_http. A continuación, abriremos el proyecto con Atom. 2. Seguidamente añadiremos los links de Bootstrap (https://v4-alpha.getbootstrap. com) en index.html para poder hacer uso de sus hojas de estilo. Consulte “087 Bootstrap: Introducción” para obtener más información. 3. Desde línea de comandos crearemos el componente HttpClientTest con el que trabajaremos: C:\Ej100_angular\054_http>ng generate component httpClientTest

    A continuación, lo añadiremos en el template del componente principal para poder visualizarlo en el navegador:

    El gran libro de Angular

    215

    src/app/app.component.html

    Servicio HttpClient: ejemplos de uso 4p5l71



    Para poder usar el servicio HttpClient en nuestros componentes, lo primero que tendremos que hacer es incluir el módulo HttpClientModule en nuestra aplicación Angular. Para ello, importaremos HttpClientModule en el módulo raíz de nuestra aplicación: src/app/app.module.ts … import {HttpClientModule} from ‘@angular/common/http’;

    @NgModule({ declarations: [ AppComponent ], imports: [ BrowserModule, HttpClientModule ], providers: [], bootstrap: [AppComponent] }) export class AppModule { }

    216

    El gran libro de Angular

    Finalmente, inyectaremos el servicio HttpClient en nuestro componente para que pueda usarlo: src/app/http-client-test/http-client-test.component.ts import { Component, OnInit } from ‘@angular/core’; import { HttpClient } from ‘@angular/common/http’;

    @Component({…}) export class HttpClientTestComponent implements OnInit { constructor(private http: HttpClient) { } ngOnInit() {

    }

    }

    El gran libro de Angular

    217

    055

    HttpClient: Operaciones Get y Post

    En este ejercicio analizaremos los métodos get() y post() de HttpClient. Estos métodos los utilizaremos para realizar peticiones HTTP tipo “get” y “post”, respectivamente. • GET(): para obtener un recurso del servidor. • POST(): para crear un recurso en el servidor. Para realizar pruebas con estas peticiones HTTP necesitaríamos un servidor remoto que ofreciera una API sobre la cual lanzarlas. Sin embargo, la creación de un backend con una API no es el objetivo de este ejercicio. Por este motivo haremos uso de JSONPlaceholder (https://jsonplaceholder.typicode.com/), una API REST pública para realizar test. Usando esta API podremos gestionar “publicaciones”, que las podríamos denir como ítems compuestos por un título, cuerpo y un identicador de .

    Importante Utilizaremos el método get() para obtener un recurso del servidor y post() para crearlo.

    En este ejercicio usaremos las siguientes rutas de la API: Método

    URL

    Descripción

    GET

    /posts

    Obtención de todas las publicaciones

    POST

    /posts

    Crear nueva publicación

    Para ver cómo funcionan los métodos get() y post(), vamos a crear ejemplos de uso en la aplicación que habíamos creado en el ejercicio anterior. Vamos a crear una función para obtener todas las publicaciones mediante el método get(), y otra para crear una nueva publicación mediante el método post(). También añadiremos botones en el template para poder llamar a estas funciones. Hay que tener en cuenta que la gestión que realiza el servidor remoto JSONPlaceholder con las peticiones de actualización es simulada. Por tanto, al realizar un post() recibiremos el identicador de la nueva publicación; sin embargo, si a continuación realizamos un get(), no recibiremos esa nueva publicación. 1. En primer lugar, abriremos el proyecto 054_http con el editor (Atom), y pondremos en marcha la aplicación ejecutando ng serve desde la línea de comandos y desde la carpeta 054_http. 218

    El gran libro de Angular

    2. A continuación, añadimos las modicaciones en el componente: src/app/http-client-test/http-client-test.component.ts import { Component, OnInit } from ‘@angular/core’; import { HttpClient } from ‘@angular/common/http’;

    @Component({…}) export class HttpClientTestComponent implements OnInit { resultadoPeticion; constructor(private http: HttpClient) { } ngOnInit() { this.get(); }

    get() { this.http.get(‘https://jsonplaceholder.typicode.com/posts’) .subscribe( data => { this.resultadoPeticion = data; } ); } post(){ this.http.post(‘https://jsonplaceholder.typicode.com/posts’, { title: ‘Previsión Viernes.’, body: ‘Parcialmente soleado.’, Id: 1 }) .subscribe( data => { this.resultadoPeticion = data; } ); } }

    src/app/http-client-test/http-client-test.component.html
    Petición: 6n69r

    Resultado: 3x4a4d
    <pre>{{resultadoPeticion|json}} El gran libro de Angular

    219

    Finalmente, desde el navegador (http://localhost:4200) podrá probar las peticiones pulsando el botón que desee en cada caso.

    Analizando la sintaxis de la llamada, seguramente ya habrá intuido que tanto get() como post() devuelven un observable sobre el que realizamos una suscripción. Y así es. Este y el resto de métodos de HttpClient para realizar peticiones HTTP devuelven observables de tipo cold. Esto signica lo siguiente: • • 220

    La petición no se realiza hasta que se hace una suscripción al observable devuelto. Cada suscripción implicará una petición nueva. El gran libro de Angular

    Si desea más información de los observables consulte el capítulo “052 Servicios: Gestión asíncrona con observables”. Por otra parte, las API no siempre nos devolverán datos en formato JSON. Si este fuera el caso, deberíamos indicarlo al realizar la petición con la parametrización correspondiente. Vea un ejemplo: this.http.get(‘/assets/cheroTexto.txt’, {responseType: ‘text’}) .subscribe(data => console.log(data));

    El gran libro de Angular

    221

    056

    HttpClient: Operaciones put, patch y delete

    Continuando el análisis de métodos de HttpClient, en este ejercicio analizaremos los métodos put(), patch() y delete(), que usaremos para realizar peticiones HTTP de tipo “put”, “path” y “delete”, respectivamente. • •



    PUT(): para actualizar un recurso del servidor. PATCH(): para actualizar, de forma parcial, un recurso del servidor. Lo utilizaríamos cuando, por ejemplo, solamente necesitáramos actualizar una propiedad del recurso. DELETE(): para eliminar un recurso del servidor.

    Importante Utilizaremos put() y patch() para actualizar recursos del servidor de forma total o parcial, respectivamente, y delete() para eliminarlos.

    Vamos a probar todos estos métodos sobre la aplicación con la que estábamos trabajando anteriormente. Para ello, haremos uso de las siguientes rutas de la API REST de JSONPlaceholder (https://jsonplaceholder.typicode.com/): Método

    URL

    Descripción

    PUT

    /posts/:id

    Actualizar una publicación.

    PATCH

    /posts/:id

    Actualizar parcialmente una publicación. Actualizar un subconjunto de propiedades.

    DELETE

    /posts/:id

    Eliminar una publicación.

    En los tres casos, “:id” correspondería al identicador de la publicación sobre la cual queremos realizar la acción. Vamos a realizar los cambios: 1. En primer lugar, abriremos el proyecto 054_http con el editor (Atom), y pondremos en marcha la aplicación ejecutando ng serve desde la línea de comandos y desde dentro la carpeta 054_http. 2. A continuación, añadimos las modicaciones en el componente:

    222

    El gran libro de Angular

    src/app/http-client-test/http-client-test.component.ts … @Component({…}) export class HttpClientTestComponent implements OnInit { resultadoPeticion;

    constructor(private http: HttpClient) { } … put(){ this.http.put(‘https://jsonplaceholder.typicode.com/posts/1’, { id: 1, title: ‘Previsión Lunes’, body: ‘Lluvias.’, Id: 1 }) .subscribe( data => { this.resultadoPeticion = data; } ); } patch(){ this.http.patch(‘https://jsonplaceholder.typicode.com/posts/1’, { body: ‘Soleado.’ }) .subscribe( data => { this.resultadoPeticion = data; } ); } delete(){ this.http.delete(‘https://jsonplaceholder.typicode.com/posts/1’) .subscribe( data => { this.resultadoPeticion = data; } ); } }

    El gran libro de Angular

    223

    src/app/http-client-test/http-client-test.component.html
    Petición: 6n69r

    Resultado: 3x4a4d
    <pre>{{resultadoPeticion|json}}

    Finalmente, desde el navegador (http://localhost:4200) ya podrá probar las peticiones pulsando el botón que desee en cada caso.

    224

    El gran libro de Angular

    Por último, indicar que todas las peticiones HTTP que hemos visto también pueden realizarse mediante un único método genérico: request(). Veamos, por ejemplo, cómo podríamos realizar una petición “get” mediante el método request() en sustitución del método get() que habíamos visto en el capítulo anterior: /* this.http.get(‘https://jsonplaceholder.typicode.com/posts’) .subscribe( data => { this.resultadoPeticion = data; } ); */ this.http.request(‘GET’,’https://jsonplaceholder.typicode.com/posts’) .subscribe( data => { this.resultadoPeticion = data; } );

    El gran libro de Angular

    225

    057

    HttpClient: Conguraciones adicionales sobre las peticiones HTTP

    En este ejercicio analizaremos algunas conguraciones adicionales que podemos aplicar a las peticiones HTTP antes de que se envíen al servidor remoto. Los ejemplos que veremos los implementaremos sobre la aplicación creada en los anteriores ejercicios, por lo que recuerde abrir el proyecto 054_http con el editor (Atom) y poner en marcha la aplicación ejecutando “ng serve” desde 054_http en línea de comandos. Añadir parámetros en el URL

    Importante Con HttpParams podremos añadir parámetros a nuestras peticiones HTTP realizadas con HttpClient. Y con HttpHeaders, cabeceras personalizadas.

    Normalmente, en las API existen algunos “endpoint” que aceptan parámetros que condicionan la operativa que se va a realizar. Por ejemplo, en el caso de la API REST JSONPlaceholder (https://jsonplaceholder.typicode.com/) que hemos usado en los anteriores ejercicios, existe una ruta mediante la cual podemos indicar que solamente queremos las publicaciones de un determinado : Método

    URL

    Descripción

    GET

    /posts

    Obtención de todas las publicaciones

    GET

    /posts?I - Obtención de las publicaciones del d=:id con Id = :id

    Con HttpClient, podemos realizar llamadas con parámetros usando la clase HttpParams. Veamos cómo usarla a través de un ejemplo: 1. Sobre nuestra aplicación, crearemos una nueva llamada get() para la ruta “/ posts?Id=:id” de JSONPlaceholder, indicando que queremos las publicaciones del con “Id” = 9. Una vez introducido el código, realice la llamada desde el navegador y compruebe su funcionamiento.

    226

    El gran libro de Angular

    src/app/http-client-test/http-client-test.component.ts import { Component, OnInit } from ‘@angular/core’; import { HttpClient, HttpParams } from ‘@angular/common/http’;

    @Component({…}) export class HttpClientTestComponent implements OnInit { … get_param() { const params = new HttpParams().set(‘Id’, ‘9’); this.http.get(‘https://jsonplaceholder.typicode.com/posts’, {params}) .subscribe( data => { this.resultadoPeticion = data; } ); } }

    src/app/http-client-test/http-client-test.component.html …

    HttpParams es inmutable, lo que signica que las llamadas a sus métodos no modican el objeto, sino que devuelven de nuevo. Por este motivo, en el anterior El gran libro de Angular

    227

    ejemplo tenemos la creación y conguración del objeto HttpParams en una misma instrucción. Un código como el siguiente no crearía un objeto HttpParams como el anterior, sino que crearía dos objetos HttpParams (aunque, para el segundo, no habríamos guardado ninguna referencia): el primer objeto no tendría parámetros y el segundo tendría uno. const params = new HttpParams(); params.set(‘param1’, “value1”);

    Añadir cabecera personalizada En ciertos contextos necesitaremos añadir cabeceras personalizadas en nuestras peticiones HTTP. Un claro ejemplo de ello se produce en determinados sistemas de seguridad. En ellos, necesitaremos añadir una cabecera de autorización en todas las peticiones HTTP que realicemos. En esa cabecera, añadiríamos un “token” (o ) que permitiría al servidor remoto identicarnos para que este haga sus gestiones o las deniegue. Con HttpClient, podemos añadir cabeceras personalizadas usando la clase HttpHeaders. Veamos un ejemplo: 2. Añadiremos una cabecera personalizada con un “token” de autorización sobre el método get_param() que habíamos creado en el punto anterior. src/app/http-client-test/http-client-test.component.ts import { Component, OnInit } from ‘@angular/core’; import { HttpClient, HttpParams, HttpHeaders } from ‘@angular/common/ http’;

    @Component({…}) export class HttpClientTestComponent implements OnInit { … get_param() { const headers = new HttpHeaders().set(‘Autorizacion’, ‘mi token’); const params = new HttpParams().set(‘Id’, ‘9’); this.http.get(‘https://jsonplaceholder.typicode.com/posts’, {headers, params}) .subscribe( data => { this.resultadoPeticion = data; } ); } }

    Para comprobar que se ha añadido la cabecera personalizada utilizaremos los log de Google Chrome, por lo que antes de realizar la llamada desde

    228

    El gran libro de Angular

    el navegador, deberá seleccionar la opción “Más herramientas/Herramientas para desarrolladores/Network” de Google Chrome.

    Hay que tener en cuenta que, igual que pasaba con la clase HttpParams, HttpHeaders también es inmutable.

    El gran libro de Angular

    229

    058

    HttpClient: Gestión de respuestas y errores de peticiones HTTP

    En este ejercicio analizaremos distintas gestiones que podemos realizar sobre respuestas de peticiones HTTP. Los ejemplos que veremos los implementaremos en la aplicación creada en los anteriores ejercicios, por lo que recuerde abrir el proyecto 054_http con el editor (Atom) y poner en marcha la aplicación ejecutando “ng serve” desde 054_http en línea de comandos.

    Importante Realice una buena gestión de errores de sus peticiones HTTP para tener bien monitorizadas sus aplicaciones.

    Denir tipos para las respuestas Normalmente, una petición HTTP devolverá una repuesta en formato JSON que HttpClient se encargará de parsear en un objeto. Para que ese objeto tenga propiedades vinculadas a los distintos elementos de la respuesta y así facilitarnos su gestión, será necesario que indiquemos a HttpClient el tipo o forma que tiene que tener. Veamos cómo podemos hacerlo implementándolo en las llamadas de nuestra aplicación: 1. Primero crearemos la interface que dena nuestra respuesta, que en nuestro caso es una publicación. Crearemos el archivo post.ts y le añadiremos el siguiente código: src/app/post.ts export interface Post { Id: number; id: number; title: string; body: string; }

    2. A continuación, usaremos la interface para denir el tipo de respuesta en cada una de las llamadas. Esto, por ejemplo, nos permitirá que en la llamada a “post” podamos mostrar por log el identicador de la publicación creada accediendo a la propiedad “id” del objeto data:

    230

    El gran libro de Angular

    src/app/http-client-test/http-client-test.component.ts import { Post } from ‘../post’; … this.http.get (‘https://jsonplaceholder.typicode.com/ posts’) .subscribe( data => { this.resultadoPeticion = data; } ); … this.http.post (‘https://jsonplaceholder.typicode.com/ posts’,{…}) .subscribe( data => { this.resultadoPeticion = data; console.log(“Id. de la nueva publicación: “ + data.id)} ); …

    Desde el navegador, pulsando la opción “post”, podrá comprobar su funcionamiento.

    Leer la respuesta completa Por defecto, los métodos de HttpClient solamente devuelven la parte que forma el cuerpo (body) de la respuesta. Sin embargo, en algunos casos puede ser que nos interese ver la respuesta entera para consultar la cabecera o algún código de estado. Veamos cómo lo podríamos hacer.

    El gran libro de Angular

    231

    3. Vamos a indicar en la llamada get() que queremos recibir la respuesta entera. Fíjese que, ahora, en la variable “resultadoPetición” debemos asignarle “data.body” y no “data”. src/app/http-client-test/http-client-test.component.ts … this.http.get (‘https://jsonplaceholder.typicode.com/posts’, {observe:’response’}) .subscribe( data => { this.resultadoPeticion = data.body; console. log(data);} );

    Desde el navegador podrá comprobar que al pulsar “get” recibimos el mensaje entero.

    Gestión de errores Los métodos de HttpClient devuelven observables, y tal como explicábamos en el capítulo de los observables (“052 Servicios: Gestión asíncrona con observables”), la gestión de errores se realizará añadiendo un controlador de error en la suscripción. Veamos un ejemplo. 1. Vamos a ponerlo en práctica primero añadiendo un control de error en la llamada a “put”, y luego provocando un error jando la actualización de una publicación inexistente (id publicación = 1.000):

    232

    El gran libro de Angular

    src/app/http-client-test/http-client-test.component.ts … this.http.put (‘https://jsonplaceholder.typicode.com/ posts/1000’,{…}) .subscribe( data => { this.resultadoPeticion = data; }, err

    => { console.log(err); });

    El error devuelto es de tipo HttpErrorResponse, y podemos obtener más detalles de ese error accediendo a sus propiedades. Por otra parte, en una petición HTTP se pueden producir dos grandes tipos de errores: error de cliente o red, o sea, error en el canal de comunicación, y error devuelto por el servidor remoto. Es recomendable que se gestionen por separado. Veamos cómo hacerlo. 1. Para los errores de cliente o red, la propiedad “error” del objeto HttpErrorResponse es de tipo Error, por lo que para gestionar los dos tipos de error añadiremos el siguiente código: src/app/http-client-test/http-client-test.component.ts … this.http.put (‘https://jsonplaceholder.typicode.com/ posts/1000’,{…}) .subscribe( data => { this.resultadoPeticion = data; }, (err: HttpErrorResponse)

    => {

    if (err.error instanceof Error){ console.log(‘Error cliente o red:’, err.error.message); } else { console.log(`Error servidor remoto. ${err.status} # ${err. message}`); } });

    Pulsando la opción “put” de la aplicación podrá comprobar cómo se gestiona correctamente el error de publicación inexistente (http 404 not found).

    El gran libro de Angular

    233

    059

    HttpClient: Intercepción de peticiones y respuestas

    Una característica importante del módulo HttpClient (“HttpClientModule”) es la intercepción, la posibilidad de crear interceptores de mensajes entre el frontend y backend para poderlos modicar, monitorizar, etc. Para crear un interceptor declararemos una clase decorada con @Injectable() y que implemente la interfaz HttpInterceptor. La implementación de la interfaz requiere que añadamos el método intercept() en nuestra clase. Veamos un ejemplo de interceptor que simplemente realiza un log de la petición interceptada:

    Importante Los interceptores nos permitirán interceptar los mensajes transmitidos entre aplicación y backend para poder modicarlos y monitorizarlos.

    @Injectable() export class TestInterceptor implements HttpInterceptor { intercept (req: HttpRequest , next: HttpHandler): Observable > { console.log(req); return next.handle(req); } }

    El método “intercept” tiene dos parámetros de entrada: req (petición) y next (“siguiente controlador”). El procedimiento sería el siguiente. El interceptor realiza las acciones que convengan sobre la petición interceptada (req) y realiza la llamada “next.handle(req)”. Esta llamada tiene que realizarse para que el resto de interceptores (en caso que los tuviéramos) procesen la petición y para que esta acabe realizándose. Por último indicar que la llamada “next.handle(req)” devuelve un observable para la respuesta de la petición. Este observable también deberá devolverse por nuestro método “intercept”. Vamos a practicar con los interceptores en nuestra aplicación. Crearemos dos interceptores. El primero añadirá un “token” de autenticación en la cabecera de la petición. El segundo simplemente mostrará esta petición y su respuesta en el log. En el capítulo “057 HttpClient: Conguraciones adicionales sobre las peticiones HTTP” ya habíamos visto cómo añadir una cabecera de autenticación en una petición; sin

    234

    El gran libro de Angular

    embargo, aquí, al hacerlo desde de un interceptor, podremos aplicarlo de forma automática para todas las peticiones que realicemos. 1. Primero abriremos el proyecto 054_http con el editor (Atom), y, desde la carpeta 054_http, pondremos en marcha la aplicación ejecutando ng serve. 2. Desde el editor (Atom), nos situaremos sobre la carpeta app y crearemos el chero testInterceptor.ts. Dentro, añadiremos el código del primer interceptor: src/app/testInterceptor.ts import { Injectable } from ‘@angular/core’; import { HttpEvent, HttpInterceptor, HttpHandler, HttpRequest} from ‘@angular/common/http’; import { Observable } from ‘rxjs/observable’;

    @Injectable() export class TestInterceptor implements HttpInterceptor { intercept (req: HttpRequest , next: HttpHandler): Observable > { const modReq = req.clone({headers: req.headers.set(‘tI_ Autorizacion’,’token’)}); return next.handle(modReq); } }

    De este código cabe destacar lo siguiente. Las clases HttpRequest y HttpResponse son inmutables, no podemos modicarlos. Por este motivo, las modicaciones las realizamos sobre un clon o duplicado de la petición original. Esto es así para evitar que, en operaciones de reenvío, peticiones modicadas por la cadena de interceptores vuelvan a entrar, ya modicadas, por la misma cadena. 3. Seguidamente crearemos el segundo interceptor “testInterceptor2.ts” con el siguiente código:

    El gran libro de Angular

    235

    src/app/testInterceptor2.ts … @Injectable() export class TestInterceptor2 implements HttpInterceptor { intercept (req: HttpRequest , next: HttpHandler): Observable > { console.log(req); return next .handle(req) .do(event => { if (event instanceof HttpResponse) { console. log(event);} }); } }

    El operador do() de la librería RxJS agrega un efecto secundario a un observable sin afectar los valores en la secuencia. Aquí lo usamos para detectar el evento HttpResponse, o sea, la respuesta a la petición realizada, y mostrarlo por el log. 4. Para activar los interceptores en nuestra aplicación deberemos congurarlos en el modulo principal. Esto lo haremos de la siguiente forma: src/app/app.module.ts import { HTTP_INTERCEPTORS } from ‘@angular/common/http’; … @NgModule({ declarations: […], imports: […], providers:[{ provide: HTTP_INTERCEPTORS, useClass: TestInterceptor, multi: true }, { provide: HTTP_INTERCEPTORS, useClass: TestInterceptor2, multi: true }],… })…

    El orden establecido en la conguración de los interceptores determinará su orden de ejecución, por tanto, la petición que veremos en el log ya contendrá la cabecera de seguridad. 5. Ejecutando las distintas llamadas implementadas podrá comprobar el funcionamiento de los interceptores. Por ejemplo, pulsando “post”, podrá comprobar cómo aparecen petición y respuesta en el log. Además, si analiza la petición, podrá comprobar que incluye la cabecera de seguridad

    236

    El gran libro de Angular

    El gran libro de Angular

    237

    060

    HttpClient: Combinación y sincronización de peticiones HTTP. Eventos de progreso

    Los ejemplos que veremos a continuación, los implementaremos sobre la aplicación creada en los anteriores ejercicios, por lo que recuerde abrir el proyecto 054_http con el editor (Atom) y poner en marcha la aplicación ejecutando “ng serve” desde 054_http en línea de comandos. Lanzar peticiones HTTP en paralelo combinando su resultado

    Importante Utilice todo el potencial de la librería RxJs para gestionar las peticiones HTTP según sus necesidades.

    Para lanzar varias peticiones HTTP en paralelo y combinar su resultado podemos usar el operador fork de la librería RxJs. Veamos un ejemplo: 1. Crearemos una nueva llamada para lanzar dos “get” sobre las publicaciones 4 y 5. src/app/http-client-test/http-client-test.component.ts peti_paral() { Observable.fork( this.http.get (‘https://jsonplaceholder.typicode.com/ posts/4’).delay(3000), this.http.get (‘https://jsonplaceholder.typicode.com/ posts/5’) ).subscribe( data => { this.resultadoPeticion = data;} ); } src/app/http-client-test/http-client-test.component.html

    Una vez introducido el código, realice la llamada desde el navegador y compruebe su funcionamiento. Podrá comprobar que, pasados 3 segundos (debido al delay del primer “get”), se visualizan los datos. “fork” nos permite combinar varios observables, obtenidos de peticiones HTTP, en un nuevo observable. Este último emitirá una cadena con el último valor emitido por cada uno de los observables cuando todos ellos hayan acabado. Si los observables emitiesen más de un valor, solamente se tendría en cuenta el último. 238

    El gran libro de Angular

    Lanzar peticiones HTTP en secuencia Un caso de uso común es el de lanzar una petición HTTP, recoger su resultado y, nalmente, usarlo para realizar otra petición HTTP. Esta secuencia de peticiones la podemos hacer usando el operador switchMap de la librería RxJs. Veamos un ejemplo: 1. Crearemos una nueva llamada para obtener una publicación, modicarla y transferirla: src/app/http-client-test/http-client-test.component.ts peti_sec() { this.http.get (‘https://jsonplaceholder.typicode.com/ posts/1’) .switchMap( data => { data.title = “(MODIFICADO) “ + data.title; return this.http.put (‘https://jsonplaceholder.typicode. com/posts/1’,data)}) .subscribe( data => { this.resultadoPeticion = data;} ); }

    src/app/http-client-test/http-client-test.component.html

    El gran libro de Angular

    239

    Una vez introducido el código, realice la llamada desde el navegador y compruebe su funcionamiento.

    “switchMap” es parecido al operador “map” que vimos en el capítulo 053. Sin embargo, debemos usar “switchMap” cuando la función de transformación devuelva un observable y “map” cuando devuelva un valor. Eventos de progreso Hasta este momento todas las peticiones HTTP que hemos visto se realizaban de forma muy rápida porque el tamaño de los mensajes transmitidos era muy pequeño. Sin embargo, habrá veces que necesitemos transferir un mensaje mucho más grande que necesite cierto tiempo. En estos casos, siempre es bueno poder indicar al el progreso de esa transferencia. Para poder hacerlo, deberemos capturar los eventos de progreso y lo haremos realizando las peticiones con el método genérico “request(HttpRequest)” (si desea más información consulte el capítulo 056) y la opción reportProgres. Veamos un ejemplo: 1. Crearemos una nueva llamada que realizará un “post” y capturaremos los eventos:

    240

    El gran libro de Angular

    src/app/http-client-test/http-client-test.component.ts post_prgEvents() { const request = new HttpRequest(“POST”, “https:// jsonplaceholder.typicode.com/posts”, {title: ‘Crítica de la película’, body: ‘Me ha gustado mucho.’, Id: 1}, {reportProgress: true}); this.http.request(request) .subscribe( event => { if (event.type === HttpEventType.Progress) { const percentDone = Math.round(100 * event. loaded / event.total); console.log(`Fichero transferido en un ${percentDone}%`); } else if (event.type === HttpEventType.Response) { this.resultadoPeticion = event.body; } } ); } src/app/http-client-test/http-client-test.component.html

    Compruebe su funcionamiento. El mensaje del ejemplo es muy pequeño y con un solo log se indica que el chero se ha transferido al 100%, pero con uno de más grande, veríamos más log de progreso de transferencia.

    El gran libro de Angular

    241

    061

    Forms: Introducción

    Los formularios son uno de los elementos más importantes en las aplicaciones de gestión ya que son, en esencia, los que nos permiten obtener y mostrar información para registrarla o realizar acciones a partir de la misma. En HTML disponemos de un buen conjunto de elementos mediante los cuales podemos fabricar nuestros formularios, entre los que destacamos los siguientes: input, select, radio button, textarea, checkbox, buttons, etc.

    Importante Use form-group para incluir campos en formularios asociando a cada elemento su etiqueta (label) en el mismo grupo.

    Los inputs poseen una gran variedad de tipos donde, además de los clásicos text, y number, podemos enumerar los siguientes: color, date, datetime-local, email, month, range, search, tel, time, url, week, etc. En función del tipo de input indicado, se facilita el tratamiento del tipo de dato relacionado con el mismo. Por ejemplo, si indicamos un tipo number, veremos que en el input solo se pueden introducir números. Cada elemento puede llevar asociados una serie de eventos mediante los cuales podemos realizar acciones, ya sea desde el propio template o desde su componente asociado. Los atributos más clásicos que pueden asociarse a muchos de los tipos son: value, disabled, max, maxlength, min, pattern, readonly, required, size, step. Una buena práctica es incluir cada campo en un div al que asociaremos la clase form-group y en el que denamos una etiqueta y el propio control a utilizar. Al control le asociaremos también la clase form-control. Veamos un ejemplo:


    242

    El gran libro de Angular

    En el siguiente ejercicio realizaremos una aplicación en la que incluiremos algún ejemplo de los elementos comentados anteriormente. 1. En primer lugar, nos ubicaremos en Ej100_angular y crearemos el proyecto tecleando ng new formIntro. 2. Seguidamente, renombraremos el proyecto ubicándonos en Ej100_angular, y escribiendo lo siguiente: C:\Ej100_angular>rename formIntro 061_formIntro A continuación, abrimos el proyecto con nuestro editor y modicamos el título de la aplicación que se halla en la clase AppComponent del chero app.component.ts: export class AppComponent { title

    = ‘061 formIntro’;

    } Para usar las clases de Bootstrap, modicaremos el chero app.component.html para que, de momento, tenga el siguiente contenido:

    {{title}} 49413a


    Ahora nos ubicaremos en 061_formIntro y arrancaremos la aplicación tecleando lo siguiente: C:\Ej100_angular>cd 061_formIntro C:\Ej100_angular\061_formIntro >ng serve

    El gran libro de Angular

    243

    A continuación, incluiremos los tags correspondientes al form y, dentro de los mismos, añadiremos el primer control de nuestro formulario que será por ejemplo “código”:


    La clase marco la deniremos también en nuestro archivo styles.css con el siguiente contenido: .marco { border: 3px solid blue; }

    Guardamos y actualizamos el navegador para ver cómo queda.

    3. A continuación, añadiremos unos cuantos controles más para tener un formulario con una muestra de los controles más típicos. Así pues, añadimos un control para los campos nombre (input text), edad (input number)), opción (select), sexo (radiobutton), comentarios (textarea), activar (checkbox) y submit (button). 4. Guardamos y actualizamos el navegador para ver cómo queda.

    244

    El gran libro de Angular

    5. Seguidamente, añadimos el atributo placeholder al campo nombre para indicar al qué es lo que hay que introducir en el mismo: El gran libro de Angular

    245



    Añadimos al código una restricción para que no se puedan introducir más de 6 caracteres usando maxlength:

    Incluimos un valor por defecto, un máximo y mínimo para la edad añadiendo los atributos value, min y max:

    246

    El gran libro de Angular

    062

    Forms: Obtención de valores

    Para acceder a los valores introducidos en los controles de un formulario, podemos utilizar diversos mecanismos. Uno de los mecanismos es el uso de variables locales que hagan referencia a los controles. Para poder trabajar con las propiedades de un control añadimos en su tag la denición #nomVar, la propiedad name y ngModel. Por ejemplo, para un supuesto control denominado nombre, usaríamos una expresión como la siguiente:

    Importante Use binding para poder modicar el valor de una propiedad de forma bidireccional (del template a la clase del componente y viceversa).



    Podemos comprobar que es posible utilizar nom en nuestro template mostrando su valor mediante interpolación (nom {{ nom.value }}). Otra posibilidad es realizar un binding (two-way data binding) para poder modicar el valor de una propiedad de forma bidireccional. Adaptando el ejemplo anterior, podríamos crear una variable name en nuestro archivo component.ts asociado al template y en el template denir lo siguiente:

    En el siguiente ejercicio, usaremos los controles del ejercicio anterior (Forms_Introduccion_Controles). 1. Nos ubicamos en Ej100_angular, crearemos el proyecto tecleando ng new formValores y, seguidamente, renombraremos el proyecto ubicándonos en Ej100_angular, y escribiendo lo siguiente: C:\Ej100_angular>rename formValores 062_formValores

    El gran libro de Angular

    247

    A continuación, copiamos los archivos src/app/app.component.html y src/styles.css del ejercicio anterior (formIntro) y los pegamos en nuestro proyecto 062_formValores reemplazando los existentes. 2. Abrimos el proyecto y modicamos el título de la aplicación (dentro de app.component.ts): export class AppComponent { title

    = ‘062 formValores’;

    }

    Ahora nos ubicaremos en 062_formValores, arrancaremos la aplicación y teclearemos lo siguiente: C:\Ej100_angular>cd 062_formValores C:\Ej100_angular\061_formIntro >ng serve

    A continuación, vamos a añadir una variable local para código deniendo lo siguiente:

    Envolvamos el div que contiene el formulario en un row para mostrar 2 div: el div de formulario y el div que mostrará valores de la siguiente manera:


    El div que contiene el formulario ocupará 5 columnas (col-5) y en el div de variables incluiremos: Cod: {{ cod.value }} 248

    El gran libro de Angular

    Guardamos el archivo y observamos como se muestra el contenido del campo código.

    3. Ahora, obtendremos el valor del campo codigo y usando “two-way data binding” creando una variable en la clase AppComponent de la siguiente manera: export class AppComponent { title = ‘062 formValores’; codigo: string = “”; }

    En nuestro tag input, introduciremos lo siguiente:

    En el div donde mostramos valores, tendremos:
    Cod: {{ cod.value }}
    Codigo: {{ codigo }}


    Guárdelo todo y observe cómo se ve en el navegador.

    El gran libro de Angular

    249

    4. A continuación, crearemos una función (mostrarVar()) en nuestro componente, la cual, simplemente, mostrará por consola el contenido de la variable codigo de nuestro formulario y que asociaremos al evento change del control codigo. En la clase AppComponent añadiremos lo siguiente: export class AppComponent { title = ‘062 formValores’; codigo: string = “”; mostrarVar() { console.log(“Codigo (“ + this.codigo + “)”); } }

    En el tag input asociado al codigo añadiremos:

    Muestre la consola (herramientas de desarrollador) del navegador (p. ej., en Google Chrome pulse ALT+MAYUS+I) y visualice el contenido de código al introducir un valor y cambiar el foco.

    5. Dena también nombre, edad, opción, sexo, comentarios y activar, añadiendo en cada uno el binding ([(ngModel)]= “campo”), name (name=“campo”) y la llamada a la función mostrarVar() mediante el evento change. En el componente, añada una variable por cada campo a tratar, dena un valor por defecto y muéstrelos en la consola. Añada la función onSubmit para asociarla al evento Submit del formulario.

    250

    El gran libro de Angular

    6. Muestre a través de la interpolación el contenido de las variables en el div creado a tal efecto.

    7. Por último, asocie al tag form la llamada a onSubmit mediante el evento ngSubmit y cree una variable local (miForm) para el formulario:
    El gran libro de Angular

    251

    Muestre la variable miForm (miForm {{ miForm.value | json }}) aplicando un pipe con json para ver el contenido del objeto en el div donde venimos mostrando los valores: Activar: {{ activar }}
    miForm {{ miForm.value | json }}


    Añada un valor a cada campo y compruebe cómo se muestra su contenido en el template y en la consola. Pruebe el botón Submit para ver que se ejecuta la función de nuestro componente onSubmit.

    252

    El gran libro de Angular

    063

    Forms: Estado de los objetos

    El estado de los objetos viene determinado por un conjunto de clases que nos permitirá averiguar si los objetos de un formulario han sido tratados o modicados o sin son válidos o no respecto de sus posibles restricciones.

    Importante Compruebe el estado cuando quiera realizar alguna validación o detectar alguna situación respecto a un control.

    En el ejercicio destinado a validaciones veremos algunos de sus posibles usos, pero en este ejercicio, nos vamos a dedicar a presentarlos y explicar cuál es la información que nos aportan. Los estados más importantes de un objeto están representados por alguna de las siguientes clases: Clases

    Estado del control

    ng-touched

    Ya ha tenido el foco en algún momento.

    ng-untouched

    Aún no ha tenido el foco.

    ng-dirty

    Se ha hecho alguna modicación.

    ng-pristine

    Aun no se ha modicado nada.

    ng-valid

    Posee un contenido válido.

    ng-invalid

    Posee un contenido inválido.

    ng-pending

    Validaciones asíncronas pendientes.

    Un objeto posee varias clases asociadas simultáneamente, aunque algunas de ellas son incompatibles entre sí como pueden ser ng-touched con ng-untouched, ng-dirty con ng-pristine, o ng-valid con ng-invalid. En el siguiente ejercicio realizaremos una aplicación sencilla en la que incluiremos algunos controles que nos ayudarán a entender el funcionamiento de estas clases. 1. Nos ubicaremos en Ej100_angular y crearemos el proyecto tecleando ng new formEstado. 2. Seguidamente, renombraremos el proyecto ubicándonos en Ej100_angular, y escribiendo lo siguiente: El gran libro de Angular

    253

    C:\Ej100_angular>rename formEstado 063_formEstado A continuación, abrimos el proyecto con nuestro editor y modicamos el título de la aplicación que se halla en la clase AppComponent del chero app.component.ts: export class AppComponent { title = ‘063 formEstado’; } Para usar las clases de Bootstrap, incluiremos en el chero app.component.html lo siguiente:

    {{title}} 49413a


    Ahora nos ubicaremos en 063_formEstado y arrancaremos la aplicación tecleando lo siguiente: C:\Ej100_angular>cd 063_formEstado C:\Ej100_angular\061_formIntro >ng serve A continuación, incluiremos un div con los tags correspondientes al form y, dentro de los mismos, añadiremos el primer control de nuestro formulario que será, por ejemplo, codigo. También añadiremos otro div para mostrar las clases asociadas al control mediante className y también su propiedad value:
    Codigo clases: {{ codigo.className }}
    Codigo: {{ codigo.value }}


    254

    El gran libro de Angular

    Vemos que también hemos declarado una variable local para el form mediante #miForm=”ngForm”. Observe que, en esta ocasión, hemos incluido solo la propiedad ngModel y la variable local #codigo para podernos referir al control. Las clases marco y fondo las deniremos en nuestro archivo styles.css con el siguiente contenido: .marco { border: 3px solid green; } .fondo { border: 1px solid red; background-color: lightblue; } Guardamos y actualizamos el navegador para ver cómo queda.

    3. A continuación, añadiremos algunos controles más (nombre, email y movil) para tener un formulario más variado y aprovechamos para agrupar los campos email y movil y mostrar un ejemplo de agrupación. Para agrupar varios campos, los incluiremos en un div al que asignaremos la propiedad ngModelGroup y también una variable local (#o) con la que reconocer dicha agrupación:


    El gran libro de Angular

    255

    En el div donde mostramos las clases asociadas a cada control y su contenido, añadiremos una línea para cada control.

    4. Guardamos y actualizamos el navegador para ver cómo queda.

    256

    El gran libro de Angular

    5. Podemos observar que el código muestra las variables: form-control nguntouched ng-pristine ng-invalid. ng-invalid es mostrado porque hemos incluido el atributo required y, de momento, está vacío. ngpristine se muestra porque el contenido del control no ha variado desde que se mostró el formulario por primera vez. Y ng-untouched se muestra porque aún no ha tenido el foco en ningún momento. 6. Si hacemos clic con el ratón sobre el campo codigo e introducimos el valor ‘1’, observamos como ahora aparecen otras clases, ya que el control ha sido tocado (ng-touched), se ha modicado su valor inicial (ng-dirty) y se ha convertido en válido (ng-valido), ya que es requerido y no está vacío.

    7. Rellenemos el resto de controles (nombre, email y movil) y veamos cómo muestran sus valores el div del pie de página y también cómo se visualiza el contenido de cada uno de los controles del form gracias a la sentencia {{ miForm.value | json }}.

    El gran libro de Angular

    257

    064

    Forms: Validaciones

    Las validaciones en los formularios son imprescindibles para poder recoger la información con la calidad necesaria antes de enviarla para su procesamiento posterior. Podemos realizar tantas validaciones como sean necesarias en cada uno de los controles que queramos y habilitar o deshabilitar el botón Submit del formulario dependiendo de si hay o no errores en el formulario. En el siguiente ejercicio crearemos un formulario sencillo solo con dos campos que nos permitirán analizar los detalles básicos y más importantes sobre las validaciones.

    Importante Valide cada una de las introducciones de los formularios para garantizar la calidad de los datos recogidos y no envíe el formulario hasta que esté completamente validado.

    1. Nos ubicaremos en Ej100_angular y crearemos el proyecto tecleando ng new formValida. 2. Seguidamente, renombraremos el proyecto ubicándonos en Ej100_angular, y escribiendo lo siguiente: C:\Ej100_angular>rename formValida 064_formValida

    Abrimos el proyecto y modicamos el título de la aplicación en el chero app.component.ts: export class AppComponent { title

    = ‘064 formValida’;

    }

    Para usar las clases de Bootstrap, incluiremos al principio del chero app. component.html lo siguiente:

    {{title}} 49413a




    258

    El gran libro de Angular

    Importamos FormsModule en el archivo app.module.ts y lo añadimos al bloque de imports.

    3. A continuación, incluiremos 2 div en nuestro archivo app.component. html. Uno para denir el formulario y un control (código); otro para mostrar algunas propiedades de los controles y del formulario en sí. Tienen el siguiente contenido:
    Codigo clases: {{ _codigo.className }}
    Codigo: {{ codigo.value }}


    En el archivo styles.css incluimos un par de deniciones como las siguientes para los div:

    El gran libro de Angular

    259

    .marco { border: 3px solid green; } .fondo { border: 1px solid red; background-color: lightblue; }

    Ahora nos ubicaremos en 064_formValida y arrancaremos la aplicación tecleando lo siguiente: C:\Ej100_angular>cd 064_formValida C:\Ej100_angular\061_formIntro >ng serve

    Observe las clases mostradas en el div inferior y vea cómo cambian al introducir un valor en el campo codigo.

    4. Cuando el campo codigo está vacío, se muestra la clase ng-invalid. Eso denota que existe un error. Para verlo, añadimos un div y con *ngIf lo mostramos, dependiendo de si hay o no error. Así pues, vamos a añadir debajo del control de codigo, lo que resaltamos a continuación: ...
    codigo requerido


    Si el código es erróneo, se mostrará una alerta.

    260

    El gran libro de Angular

    5. Para evitar que la alerta se muestre por primera vez, añadiremos la condición de que haya tenido el foco al menos una vez. Para ello, modicaremos el *ngIf de la siguiente manera:


    Ahora no se muestra la alerta hasta que seleccionamos el control y lo abandonamos vacío. 6. A continuación, añadimos otro requisito más al código para tener 2 posibles errores. Exigimos que el código tenga una longitud mínima de 3 caracteres añadiendo minlength=”3”: ngModel #codigo=”ngModel” #_codigo required minlength=”3”>

    Ahora, matizaremos a qué error se reere cuando se detecte que el código es inválido. Vericaremos si el código ha sido modicado o no. El código de nuestras alertas quedará de la siguiente manera:
    codigo requerido
    Debe tener 3 caracteres como mínimo.
    El gran libro de Angular

    261

    Además de *ngIf visto para required, también podríamos usar [hidden] para mostrar o no el error del mínimo de caracteres dependiendo de si se da o no. Guarde el archivo y compruebe cómo funciona.

    7. Añadimos un botón Submit antes del cierre del formulario para poderlo habilitar o deshabilitar en función de si todo el formulario es válido.

    8. Añadimos también un nuevo campo denominado nombre para tener dos posibles controles a validar y modicamos el div inferior (mostrando valores) para añadir nombre y el contenido de todo el form.

    9. Observe que el botón Submit está deshabilitado gracias a la instrucción [disabled]=”!miForm.form.valid”. Efectivamente, ambos campos son requeridos y ahora están vacíos. Introduzca un valor aceptable en cada campo y compruebe cómo se habilita el botón Submit. 262

    El gran libro de Angular

    El gran libro de Angular

    263

    065

    Forms: Validaciones personalizadas

    En ocasiones, necesitamos realizar personalizaciones algo más complicadas que las mencionadas en ejercicios anteriores. Para estos casos, podemos crear una validación personalizada en la que, mediante una función, controlemos todos los detalles que sean necesarios. La idea es crear un archivo adicional que contenga la directiva que usaremos en la validación e importarla en el archivo app.module.ts. En el siguiente ejercicio crearemos una validación especial que consistirá en permitir introducir solo letras mayúsculas en el campo sobre el que la apliquemos. Para ello, utilizaremos de base el formulario desarrollado en el ejercicio anterior (formValida) y le añadiremos nuestra validación especial al campo nombre. 1. En primer lugar, nos ubicaremos en Ej100_angular y crearemos el proyecto tecleando ng new formValidaEsp. 2. Seguidamente, renombraremos el proyecto ubicándonos en Ej100_angular, y escribiendo lo siguiente: C:\Ej100_angular>rename formValidaEsp 065_formValidaEsp

    Ahora aprovecharemos algunos cheros del ejercicio anterior (formValida) y copiaremos los siguientes archivos para pegarlos en nuestro proyecto en sus respectivas carpetas: ..\src\ styles.css ..\src\app\app.component.html ..\src\app\app.module.ts A continuación, abrimos el proyecto y modicamos el título de la aplicación en el chero app.component.ts: export class AppComponent { title

    = ‘065 formValidaEsp’;

    }

    264

    El gran libro de Angular

    Guardemos el archivo y abramos el navegador para comprobar que nuestro punto de partida es idéntico al punto en el que nalizó el ejercicio anterior y que la copia ha ido perfectamente.

    3. Ahora, vamos a crear la directiva que nos permitirá realizar nuestra validación especial. Para ello, crearemos un nuevo chero denominado src\ app\validacaracteres.directive.ts con el siguiente contenido: import { Directive } from ‘@angular/core’; import { AbstractControl, NG_VALIDATORS } from “@angular/ forms”; function ltrarCaracteres(caracter:AbstractControl){ if (caracter.value == null) return null; var contenido = caracter.value; for(var i = 0; i < contenido.length; i++){ var letra = contenido.substr(i,1); var valor = letra.charCodeAt(0); if (!(valor >=65 && valor <= 90)){ return {ltrarCaracteres: true}; } } return null; } @Directive({ selector: ‘[ltrar-caracteres]’, providers:[ {provide: NG_VALIDATORS, multi: true, useValue: ltrarCaracteres} ] }) export class FiltrarCaracteres { }

    Lo más destacable en este archivo es la función ltrarCaracteres que será la que nos permitirá analizar cada uno de los caracteres introducidos en el El gran libro de Angular

    265

    campo que estemos validando y determinar si dicho carácter es una letra mayúsculas o no. Para ello, nos basaremos en el código ASCII de cada carácter de forma que, si no está comprendido entre 65 y 90, indicaremos que es un error (ltrarCaracteres: true). 4. Una vez creada la directiva, hemos de incluirla en el archivo app.module.ts.

    Importante Use validaciones personalizadas cuando necesite realizar validaciones complejas que no puedan resolverse con las validaciones que Angular propone por defecto.

    5. Seguidamente, añadimos nuestra directiva al campo nombre para que actué la validación de forma que nuestro input quedará de la siguiente manera:

    Ahora, solo nos queda añadir una alerta que se muestre cuando se introduzca algún carácter que no sea una letra en mayúsculas.

    6. Guarde el archivo y compruebe que, al introducir una letra en minúsculas, aparece un error indicando que no es posible. 266

    El gran libro de Angular

    7. Observe también que el error aparece si introducimos un carácter inválido en cualquier posición del campo.

    8. Deje el campo vacío y compruebe que también se muestra el error de “Nombre requerido”.

    9. Observe también que el botón Submit no se habilitará hasta que todo el form contenga valores válidos.

    El gran libro de Angular

    267

    066

    Forms: Reactive

    Los reactive forms o model-driven se diferencian de los template-driven en que la creación de los controles se hace en la clase del componente. Otra diferencia importante es que los reactive forms son síncronos mientras que los template-driven son asíncronos. Por otra parte, los reactive forms permiten añadir controles dinámicamente y facilitan los test unitarios. En la plantilla, simplemente deniremos los tags HTML correspondientes a los inputs, pero estos quedarán relacionados con la clase del componente gracias a formControlName y formGroupName para los controles y grupos de controles, respectivamente.

    Importante Utilice reactive forms cuando necesite crear controles dinámicamente y/o requiera realizar pruebas unitarias, ya que será mucho más fácil.

    En el siguiente ejercicio crearemos un formulario sencillo con cuatro campos de los cuales dos los trataremos de forma individual, y al nal del ejercicio los otros dos formarán un grupo. 1. Nos ubicaremos en Ej100_angular y crearemos el proyecto tecleando ng new formReactive. 2. Seguidamente, renombraremos el proyecto ubicándonos en Ej100_ angular, y escribiendo lo siguiente: C:\Ej100_angular>rename formReactive 066_formReactive

    Abrimos el proyecto y modicamos el título de la aplicación en el chero app.component.ts: export class AppComponent { title

    = ‘066 formReactive’;

    }

    Para usar las clases de Bootstrap, incluiremos al principio del chero app. component.html lo siguiente:

    268

    El gran libro de Angular

    {{title}} 49413a




    Importamos ReactiveFormsModule (y HttpModule si no lo tenemos) en el archivo app.module.ts y lo añadimos al bloque de imports.

    3. En app.component.html deniremos nuestro form y un primer control para codigo añadiendo detrás del título lo siguiente:
    Codigo: {{ codigo.value }}


    A continuación, incluiremos el siguiente código en el chero styles.css: .marco { border: 3px solid green; } .fondo { border: 1px solid red;background-color: lightblue; }

    El gran libro de Angular

    269

    Seguidamente, en el archivo app.component.ts hemos de importar: import { FormGroup, FormBuilder } from ‘@angular/forms’;

    Dentro de la clase AppComponent, deniremos una variable para el form y usaremos el constructor para inyectar FormBuilder y poder crear un objeto que represente los controles que va a tener nuestro formulario que, por el momento, solo tiene un código. La clase AppComponent contendrá lo siguiente: export class AppComponent { title = ‘066 formReactive’; form: FormGroup; constructor(private fctrl:FormBuilder ){ this.form=fctrl.group({ codigo:’’ }) } }

    Vemos la variable form que representa nuestro form y, dentro del constructor, creamos un grupo de controles que asignaremos a dicho form. 4. Ahora, solo nos queda modicar el tag form de la siguiente manera:


    Y el control de código para añadir formControlName, dejándolo así:

    Salve todos los archivos y arranque la aplicación ubicándonos en C:\Ej100_ angular\066_formReactive tecleando ng serve. Introduzca algún valor para ver cómo funciona.

    270

    El gran libro de Angular

    5. A continuación, detrás del control codigo, insertaremos los campos nombre, acion1 y acion2 en app.component.html. También añadiremos el botón Submit.

    6. En el div inferior, añadiremos la visualización de los valores de los controles añadidos y del formulario en general.

    7. En app.component.ts, también hemos de añadir la denición de los controles nuevos.

    El gran libro de Angular

    271

    8. Guarde el archivo y compruebe cómo funciona en el navegador introduciendo algunos valores.

    9. Vamos a dar funcionalidad al botón Submit y, para ello, modicaremos el tag form para que contenga lo siguiente:
    (ngSubmit)=”onSubmit()”>

    En app.component.ts, añadimos la función onSubmit() dentro de la clase AppComponent.

    10. Introduzca algunos datos y pulse Submit para ver cómo se muestran dichos datos en la consola. 11. Si quisiéramos agrupar los controles acion1 y acion2 en uno grupo denominado aciones, simplemente tendríamos que modicar el template para añadir un div que los agrupara, incluir la propiedad formGroupName, y modicar app.component.ts para añadir esta agrupación en la creación del grupo y también en onSubmit para su display en la consola. Observe 272

    El gran libro de Angular

    cómo hemos denido unos valores por defecto al denir los controles en el constructor de AppComponent.

    12. Observe también que, al pulsar Submit, se muestran los valores en la consola.

    El gran libro de Angular

    273

    067

    Forms: Reactive validaciones

    Las validaciones en los reactive forms se declaran en la denición de los controles con la siguiente sintaxis: campo:[‘valor_defecto’,Validators.XXX]

    Si solo necesita una validación, XXX se indica dicha validación (p. ej., Validators. required). Sin embargo, si necesitamos aplicar varias validaciones, XXX contendrá la palabra compose y la sintaxis será la siguiente: codigo:[‘valor_defecto’,Validators.compose([ Validators.validacion1, Validators.validacion2, Validators.validacion3 ])],

    En el siguiente ejercicio crearemos un formulario aplicando validaciones a dos campos diferentes usando en cada uno las dos sintaxis comentadas. Para la realización de este ejercicio, usaremos como punto de partida el ejercicio anterior (formReactive) al que le quitaremos los controles de aciones para simplicar el código comentado. 1. Nos ubicaremos en Ej100_angular y crearemos el proyecto tecleando ng new formRValida.

    Importante Utilice las validaciones para asegurar la calidad de los datos introducidos en un formulario. Puede utilizar en cada control, tantas validaciones como considere necesarias.

    2. Seguidamente, renombraremos el proyecto ubicándonos en Ej100_angular, y escribiendo lo siguiente: C:\Ej100_angular>rename formRValida 067_formRValida

    Copiaremos los siguientes archivos del ejercicio anterior y los pegaremos dentro de nuestro nuevo proyecto en sus respectivas ubicaciones:

    274

    El gran libro de Angular

    src\styles.css src\app\app.component.html src\app\app.component.ts src\app\app.module.ts

    Una vez copiados, abrimos el proyecto y modicamos el título en el chero app.component.ts: export class AppComponent { title

    = ‘067 formRValida;

    }

    En app.component.html eliminamos todo lo referente a aciones, es decir, el div que agrupaba los campos acion1 y acion2 y también eliminamos la visualización de sus valores en el div inferior. Por tanto, solo quedarán los controles código y nombre. Dejaremos el botón Submit tal y como está. A continuación, en el archivo app.component.ts hemos de importar la clase Validators: import { FormGroup, FormBuilder, Validators } from ‘@ angular/forms’;

    Dentro de la clase AppComponent, dejaremos lo siguiente: export class AppComponent { title = ‘067 formRValida’; form: FormGroup; constructor(private fctrl:FormBuilder ){ this.form=fctrl.group({ codigo:’’, nombre:’’ }) } onSubmit() { console.log(“codigo . “ + this.form.controls[‘codigo’].value); console.log(“nombre . “ + this.form.controls[‘nombre’].value); console.log(JSON.stringify(this.form.value)); } }

    El gran libro de Angular

    275

    Arrancamos la aplicación y comprobamos nuestro formulario con los dos campos previstos.

    3. A continuación, añadiremos un primer ltro al campo nombre para que este sea obligatorio, así: this.form=fctrl.group({ codigo:’’, nombre:[‘’,Validators.required] })

    En el archivo app.componment.html, debajo del input asociado al nombre, añadiremos un div que se visualizará condicionado a un *ngIf que vericará si el campo nombre tiene errores y si ha tenido el foco al menos una vez (touched) o ha sido modicado (dirty). En caso de error, añadiremos una alerta:
    Nombre es obligatorio.


    276

    El gran libro de Angular

    Añadiremos también la visualización de los errores asociados al campo nombre en el div inferior.

    4. En el navegador, nos situamos en el campo nombre y lo dejamos vacío (p. ej., pulsando TAB) y observamos que aparece el error.

    A continuación, vamos a añadir algunas validaciones al campo código. En esta ocasión, tendremos que usar Validators.compose y denirlo de la siguiente manera: constructor(private fctrl: FormBuilder) { this.form = fctrl.group({ codigo: [‘’, Validators.compose([ Validators.required, Validators.minLength(3), Validators.maxLength(6) ])], nombre: [‘’, Validators.required] }) }

    El gran libro de Angular

    277

    En este caso, además de indicar que el código también es obligatorio, validaremos que tenga 3 caracteres como mínimo y 6 como máximo. En el template, hemos de incluir debajo del input de codigo los div con los errores asociados.

    5. Podemos comprobar que existe un primer div que se mostrará cuando existan errores (errors) y al mismo tiempo, el control haya tenido el foco alguna vez (touched) o haya sido modicado (dirty). Dentro de este div, tenemos un div para cada una de las posibles alertas: required, minlength y maxlength.

    6. Podemos comprobar que, si introducimos un codigo válido y un nombre, el botón Submit se activa y si abrimos las herramientas de desarrollador (p. ej., con Google Chrome CTRL+MAYUS+I) veremos en la consola que se visualiza el contenido de los controles.

    278

    El gran libro de Angular

    El gran libro de Angular

    279

    068

    Forms: Reactive validaciones personalizadas

    De forma similar a como vimos en el caso de los forms template-driven, es posible realizar validaciones personalizadas apoyándonos en una clase auxiliar que disponga de una función, la cual podemos desarrollar para que verique de forma personalizada cualquier entrada de cualquier campo del formulario. En este caso, usaremos la misma función que fabricamos en el ejercicio formValidaEsp pero con algunos pequeños cambios. Recuerde que dicha función vericaba que todas las letras introducidas en el campo fuesen mayúsculas de forma que, si no lo son, generará un error.

    Importante Use validaciones personalizadas cuando necesite ltrar entradas complejas que requieran de una funcionalidad especíca.

    Para la realización de este ejercicio, usaremos como punto de partida el ejercicio anterior (formRValida) al que le añadiremos más funcionalidad relacionada con nuestra validación personalizada. 1. Para facilitar el desarrollo del ejercicio, copiaremos el ejercicio anterior 067_ formRValida sobre 068_formRValidaEsp. Podemos hacerlo a través del propio Explorador de Windows.

    2. Una vez copiado, abrimos el proyecto y modicamos el título en el chero app.component.ts:

    280

    El gran libro de Angular

    export class AppComponent { title

    = ‘068 formRValidaEsp’;

    }

    Abrimos una ventana de CMD, nos ubicamos en el directorio de la aplicación y la arrancamos con ng serve: C:\Ej100_angular\068_formRValidaEsp>ng serve

    A continuación, creamos un chero llamado validacaracteres.ts bajo la carpeta app\src.

    3. Dentro del mismo, importaremos AbstractControl y crearemos la clase FiltrarCaracteres en la que deniremos el método que usaremos para nuestra validación y que llamaremos ltrarCaracteres. Así pues, el contenido del archivo validacaracteres.ts será el siguiente:

    El gran libro de Angular

    281

    import { AbstractControl } from “@angular/forms”;

    export class FiltrarCaracteres { static ltrarCaracteres(caracter: AbstractControl) { if (caracter.value == null) return null; var contenido = caracter.value; for (var i = 0; i < contenido.length; i++) { var letra = contenido.substr(i, 1); var valor = letra.charCodeAt(0); if (!(valor >= 65 && valor <= 90)) { return { ltrarCaracteres: true }; } } return null; } }

    Lo que hacemos en el método es analizar cada uno de los caracteres recibidos en el parámetro caracter y ver si su valor ASCII está comprendido entre 65 y 90, que son los valores correspondientes a A y Z, respectivamente. 4. Seguidamente, modicaremos el chero app.component.ts para importar la clase recién creada para la validación: import { Component } from ‘@angular/core’; import { FormGroup, FormBuilder, Validators } from ‘@angular/forms’; import { FiltrarCaracteres } from “./validacaracteres”;

    @Component({ …

    282

    El gran libro de Angular

    Dentro de app.component.ts, modicaremos también el constructor para añadir al nombre la nueva validación, de forma que el constructor quedará de la siguiente manera: constructor(private fctrl: FormBuilder) { this.form = fctrl.group({ codigo: [‘’, Validators.compose([ Validators.required, Validators.minLength(3), Validators.maxLength(6) ])], nombre: [‘’, Validators.compose([ Validators.required, FiltrarCaracteres.ltrarCaracteres ])], }) }

    Es decir, conservamos la validación required y añadimos la validación especial ltrarCaracteres. 5. Por último, tendremos que añadir las nuevas alertas en el template modicando el div asociado a los errores del nombre de la siguiente manera:
    Nombre es obligatorio.


    El gran libro de Angular

    283

    Solo puede introducir letras de la A a la Z en mayusculas.


    Guardamos el archivo y vemos que, en el navegador, al situarnos sobre el campo nombre y pulsar TAB dejándolo vacío aparece el error de Nombre es obligatorio, como ya teníamos en el ejercicio anterior. También podemos comprobar que si introducimos un carácter que no sea una letra en mayúsculas, bien sea al principio del campo o en cualquier posición del contenido del campo, nos mostrará el error de “Solo puede introducir letras de la A a la Z en mayusculas”.

    284

    El gran libro de Angular

    6. Introduzca valores correctos en codigo y nombre y compruebe que se habilita el botón Submit, de forma que, al pulsarlo, se muestra en la consola de las herramientas del desarrollador del navegador (p. ej., CTRL+MAYUS+I en Google Chrome) los valores introducidos en el formulario.

    El gran libro de Angular

    285

    069

    Forms: LocalStorage

    Una de las tareas de los formularios es la de recoger datos y mostrarlos. Para ello, generalmente se utilizan bases de datos que tratamos mediante servicios. Estos temas se tratan en otros ejercicios de este libro, pero a modo de recurso sencillo queríamos mostrar la posibilidad de almacenar datos en lo que se denomina LocalStorage que viene a sustituir a las antiguas cookies y que, en denitiva, se trata de un espacio que ofrecen los navegadores para almacenar entre 2,5 y 5 Mb de información. Podemos analizar el contenido de este espacio accediendo a las herramientas de desarrolladores (en el caso de Google Chrome en el apartado Application->Storage->Local Storage). Para la realización de este ejercicio, usaremos como punto de partida el ejercicio anterior (066_formReactive) al que le añadiremos la funcionalidad necesaria para poder grabar y leer información de la LocalStorage. 1. Para facilitar el desarrollo del ejercicio, copiaremos el ejercicio anterior 066_ formReactive sobre 069_formLocalStorage. Podemos hacerlo a través del propio Explorador de Windows.

    2. Una vez copiado, abrimos el proyecto y modicamos el título en el chero app.component.ts: 286

    El gran libro de Angular

    export class AppComponent { title

    = ‘069 formsLocalStorage’;

    }

    Abrimos una ventana de CMD, nos ubicamos en el directorio de la aplicación y la arrancamos con ng serve:

    C:\Ej100_angular\069_formsLocalStorage>ng serve

    A continuación, modicaremos el archivo app.component.ts para añadir dos métodos que permitan grabar y leer datos sobre la LocalStorage de nuestro navegador. Primero, añadiremos el método grabarDatos() con el siguiente contenido: grabarDatos(){ localStorage.setItem(“codigo”, this.form.controls[‘codigo’].value); localStorage.setItem(“nombre”, this.form.controls[‘nombre’].value); localStorage.setItem(“aciones”, JSON.stringify(this.form.controls[‘aciones’].value));

    } Para almacenar un valor, vemos que usamos la expresión localStorage.setItem(clave, valor). 3. Seguidamente, añadimos la función leerDatos() con lo siguiente: El gran libro de Angular

    287

    leerDatos(){ this.form.patchValue({ ‘codigo’: localStorage.getItem(“codigo”) ? localStorage.getItem(“codigo”) : “” }); this.form.patchValue({ ‘nombre’: localStorage.getItem(“nombre”) ? localStorage.getItem(“nombre”) : “” }); this.form.patchValue({ ‘aciones’: JSON.parse(localStorage.getItem(“aciones”)) ? JSON.parse(localStorage.getItem(“aciones”)) : “” });

    } Para leer los datos, usamos la expresión localStorage.getItem(clave). En este caso usamos el operador Elvis (?) para inicializar el campo con un nulo (“”) en caso de que esté vacío en LocalStorage. 4. Para asignar el valor al control usamos el método patchValue del objeto form (FormGroup). 5. Ahora, incluiremos la llamada a grabarDatos() en el método onSubmit() justo después de la visualización de los datos por consola:

    288

    El gran libro de Angular

    Importante LocalStorage puede permitirnos almacenar cierta información (como preferencias de o ciertas características asociadas al puesto de trabajo) de forma sencilla sin necesidad de acudir a ninguna BBDD.

    onSubmit() { console.log(“codigo . “ + this.form.controls[‘codigo’].value); console.log(“nombre . “ + this.form.controls[‘nombre’].value); console.log(“aciones “ + JSON.stringify(this.form. controls[‘aciones’].value)); console.log(“form “ + JSON.stringify(this.form.value)); this.grabarDatos(); }

    Incluiremos también la llamada a leerDatos() al nal del constructor y aprovecharemos para eliminar el valor por defecto que tenían los controles en su inicialización: constructor(private fctrl:FormBuilder){ this.form = fctrl.group({ codigo: ‘’, nombre: ‘’, aciones: fctrl.group({ acion1: ‘’, acion2: ‘’ }) }) this.leerDatos(); }

    A continuación, abrimos las herramientas de desarrolladores (p. ej., en Google Chrome CTRL+MAYUS+I). Introducimos un valor en cada control y pulsamos en Submit para ver los datos introducidos en la consola.

    El gran libro de Angular

    289

    6. Dentro de las herramientas de desarrollador del navegador, buscamos el apartado Application y, dentro del mismo, el apartado de Storage -> LocalStorage -> http://localhost:4200.

    7. Vamos a modicar el nombre mediante las herramientas de desarrollo haciendo doble clic sobre el mismo y poniendo otro contenido (p. ej., cambio “Juanto” por “Juan Antonio”).

    8. Si recargamos la aplicación en el navegador, observaremos como ahora se muestra el nuevo nombre, lo que nos demuestra que, además de grabar, podemos leer.

    290

    El gran libro de Angular

    070

    MEAN: Desarrollos con MongoDB, Express, Angular y Node.js

    Tal como comentábamos en los primeros capítulos del libro, la principal característica de las aplicaciones single-page application (SPA) que desarrollamos con Angular es que la mayor parte de su funcionalidad se lleva al cliente (navegador Web). El código en servidor se usa básicamente para proveer de servicios a nuestro código cliente para, por ejemplo, dar a una base de datos. Y así es si repasamos las aplicaciones que hemos ido desarrollando hasta este momento. En ningún caso, salvo en los ejercicios relacionados con el servicio HttpClient, hemos necesitado de un backend.

    Importante MEAN stack dene el uso de las tecnologías MongodbB Express, Angular y Node para el desarrollo web. Su principal característica es que todas estas tecnologías tienen el JavaScript como lenguaje de programación común.

    En la serie de ejercicios que empezamos ahora usaremos MEAN stack para desarrollar una aplicación entera con un front-end Angular y un back-end de servicios REST de a una base de datos.

    En el mundo del desarrollo web MEAN stack dene el uso de un conjunto concreto de tecnologías que permiten el desarrollo de todas y cada una de las partes de una aplicación. Estas tecnologías son: MongoDB, Express.js, Angular, Node.js. Todas ellas se empezaron a usar de forma conjunta por un motivo muy simple y práctico: todas ellas utilizan JavaScript como lenguaje de programación. Esto facilita mucho el desarrollo y es el principal motivo de éxito de MEAN stack. Vamos a ver un poco en qué consisten las tecnologías MongoDB y Express que no habíamos visto hasta ahora. MongoDB Tradicionalmente, las aplicaciones siempre han trabajado con bases de datos relacionales como son El gran libro de Angular

    291

    Oracle, Sql Server, MySQL o PostgreSQL. Cada una de ellas tiene sus particularidades, pero al n y al cabo todas ellas trabajan con tablas, columnas, claves primarias, consultas SQL, etc. Estos sistemas son muy ables, sin embargo, pueden tener problemas de rendimiento y escalabilidad en aplicaciones que gestionan volúmenes muy grandes de datos y que son usadas por muchos s a la vez. Es por este motivo que aparecieron las bases de datos NoSQL. De entrada, la principal diferencia respecto a las bases de datos es que NoSQL es una forma de almacenamiento no estructurado: no hay tablas, no hay registros ni tampoco consultas SQL. Existen muchos sistemas de bases de datos NoSQL y la mayoría son de código abierto. Cada uno de ellos tiene sus particularidades y pueden ser muy diferentes entre ellos, sin embargo podemos considerar que existen cuatro tipos diferentes según como almacenan y gestionan los datos: orientadas a documentos, orientadas a columnas, de clave-valor y en grafo. En MEAN stack la base de datos usada es MongoDB. MongoDB es una base de datos orientada a documentos, es decir, los datos se guardan en documentos y no en registros. Estos documentos se almacenan en BSON, que es una representación binaria de JSON. Una de las principales diferencias con las bases de datos relacionales es que los documentos de una misma colección (concepto similar al de tabla en una base de datos relacional) no tienen por qué seguir un esquema. Por ejemplo, para una colección “s” podríamos tener dos documentos como los siguientes: { Nombre: “Julian”, Hijos: [{ Nombre:”Isabel”, Edad:6},{ Nombre:”Alberto”, Edad:2}]} { Nombre: “Ramon”, Apellidos: “Lopéz”, Hijos: 3}

    Como vemos, los esquemas son totalmente diferentes. El segundo documento tiene un campo nuevo, y el campo “Hijos” es de tipo distinto al del otro documento. A pesar de esto, es importante diseñar un esquema para nuestras colecciones para facilitar su gestión. De hecho, el esquema lo denirán las consultas que vayamos a realizar con más frecuencia. Ejemplo: db.s.nd({Nombre: “Ramon”}); Express Express es un framework de desarrollo de aplicaciones web para la plataforma Node.js. Su conguración básica es la siguiente:

    292

    El gran libro de Angular



    Creación de la aplicación Express y conguración del puerto para la entrada de peticiones de clientes. const app = express(); var server = app.listen(8080, function(){ console.log(‘Listening... ‘);

    });



    Conguración de las llamadas a funciones middleware para el procesamiento de las peticiones. Ejemplo: app.use((req, res, next) => {

    console.log(‘Petición recibida.’);

    next();}); app.get(‘/s’, function(req, res, next){ //res.send(‘ ’); var err = new Error(‘ ’); next(err); }); app.post(‘/s’, function(req, res, next){ res.send(‘ creado’);}); app.use((err, req, res, next) => { console.log(‘Error!’); res.status(500). send(err.message);});

    Una llamada a una función de middleware consta de los siguientes elementos: método HTTP para el que se aplica la función, vía de (ruta) para la que se aplica la función, y la propia función middleware. Las funciones middleware tienen al objeto petición (req), al objeto respuesta (res) y a la siguiente función middleware (next), y las tareas que suelen realizar son las de: • • • •

    Ejecutar código. Realizar cambios en la petición (req) y respuesta (res). Finalizar el ciclo petición/respuesta respondiendo al cliente mediante los métodos del objeto “res”. Invocar la siguiente función middleware en la pila ejecutando “next()”.

    Cuando Express recibe una petición, se ejecuta la primera función middleware que aplique según método HTTP y ruta de la petición. Por ejemplo, para una petición “post” en “/s”, el código anterior ejecutaría la primera y tercera funciones middleware, y el cliente acabaría recibiendo el texto “ creado”. Y para una petición “get” en “/s”, el mismo código ejecutaría la primera, segunda y cuarta funciones middleware, y el cliente acabaría recibiendo un error de tipo 500 (internal server error) con el texto “ ”.

    El gran libro de Angular

    293

    071

    MEAN: Creación de la aplicación Express

    Este es el primero de una serie de ejercicios que nos permitirá construir una sencilla aplicación MEAN para poder realizar la gestión (alta, baja, consulta y modicación) de “tareas” almacenadas en una tabla de base de datos MongoDB. El backend de la aplicación lo desarrollaremos con Express.js, y estará formada por una API de servicios REST para la gestión de las “tareas” de la base de datos MongoDB. Por otra parte, el frontend lo desarrollaremos con Angular, y estará formada por dos vistas: una principal con el listado de tareas y las distintas opciones de gestión, y otra para crear o modicar una tarea.

    Importante Cualquier cambio en el frontend, o sea, en la aplicación Angular, requiere un “ng build” para actualizar los archivos de la carpeta /dist.

    En este primer ejercicio construiremos la estructura básica de la aplicación. Partiendo de un proyecto Angular, conguraremos una aplicación Express.js que hará las funciones de servidor web. La aplicación gestionará todas las peticiones que le lleguen desde el navegador, ya sea para dar a la API de servicios, o para enviar la aplicación Angular al navegador. 1. En primer lugar, nos ubicaremos en Ej100_angular y crearemos el proyecto ejMean.

    2. Seguidamente, renombraremos el proyecto para que haga referencia a nuestro número de ejercicio: C:\Ej100_angular>rename ejMean 071_ejMean

    294

    El gran libro de Angular

    3. A continuación, nos ubicaremos en 071_ejMean y arrancaremos la aplicación para comprobar cómo funciona en nuestro navegador. Para ello, teclearemos lo siguiente: C:\Ej100_angular>cd 071_ejMean C:\Ej100_angular\071_ejMean>ng serve

    4. Desde la ventana de CMD, realizaremos un ctrl+c para parar la aplicación. Una vez termine, pasaremos a instalar los módulos express y body-parser en nuestra aplicación: C:\Ej100_angular\071_ejMean>npm

    install

    –save

    express

    body-parser

    5. Una vez terminada la instalación, abriremos nuestro proyecto con nuestro editor (en nuestro caso Atom), y crearemos el archivo server.js en la raíz de nuestro proyecto. Luego, añadiremos su código:

    El gran libro de Angular

    295

    server.js // Get dependencies const express = require(‘express’); const path = require(‘path’); const http = require(‘http’); const bodyParser = require(‘body-parser’);

    //////////////////////////////////////////////////////// // Creamos la aplicacion express y la conguramos... const app = express();

    // Parsers for POST data app.use(bodyParser.json()); app.use(bodyParser.urlencoded({ extended: false }));

    //Cfg. del directorio ‘dist’ como directorio estatico. //En este directorio tendremos los archivos obtenidos en el build de nuestra aplicación Angular app.use(express.static(path.(__dirname, ‘dist’)));

    //Cfg. de las rutas app.get(‘/api’, (req, res) => { res.send(‘La API funciona’); });

    app.get(‘*’, (req, res) => { res.sendFile(path.(__dirname, ‘dist/index.html’)); });

    //Cfg. del puerto de escucha const port = process.env.PORT || ‘3000’; app.set(‘port’, port);

    //Creamos el servidor http con la aplicación express y abrimos puerto const server = http.createServer(app); server.listen(port, () => console.log(`API running on localhost:${port}`));

    6. El código anterior establece una simple aplicación Express con las siguientes características: 296

    El gran libro de Angular

    a. Puerto de escucha de peticiones: puerto 3000. b. La devolución de un texto para las peticiones que le lleguen por la ruta “/ api”. c. La devolución de la página dist/index.html (página principal de nuestra aplicación Angular) para las peticiones que le lleguen por cualquier otra ruta. 7. Antes de ejecutar nuestra aplicación Express, deberemos realizar un build para generar la archivos de la aplicación Angular en la carpeta /dist: C:\Ej100_angular\071_ejMean>ng build

    Es importante tener en cuenta que, a partir de ahora, siempre que modiquemos la aplicación Angular, deberemos realizar un “ng build” para actualizar la carpeta /dist, de tal manera que la aplicación Express envíe siempre la última versión al navegador. Es recomendable salir del editor Atom al hacerlo, ya que si no pueden producirse errores de permisos. 8. Finalmente ejecutaremos nuestra aplicación Express de la siguiente manera: C:\Ej100_angular\071_ejMean>node server.js

    9. Desde el navegador llamaremos a la aplicación por el puerto 3000. Por defecto, la aplicación Express nos devolverá la aplicación Angular. Pero si a la ruta añadimos “/api”, nos devolverá el texto codicado.

    El gran libro de Angular

    297

    072

    MEAN: Instalación y conguración de MongoDB

    En este ejercicio nos centraremos en el subsistema MongoDB del MEAN stack, o sea, en el tipo de base de datos que se usa en las aplicaciones MEAN. Descargaremos MongoDB, lo instalaremos, conguraremos y nalmente añadiremos el código necesario en nuestra aplicación para que se conecte a MongoDB. 1. El primer paso será descargar el instalador de MongoDB en nuestro ordenador desde la siguiente página: https://www.mongodb.org/ s#production En esta página, seleccionaremos la opción que más nos interese según nuestro SO. En nuestro caso, seleccionaremos la opción Windows Server 2008 64-bit, without SSL x64 que es la versión para Windows Vista o superior. Una vez seleccionada la opción adecuada, descargaremos el instalador y lo ejecutaremos seleccionando las opciones por defecto.

    298

    El gran libro de Angular

    Importante En c:\mongodb\ data\log\mongod. log tenemos los log del servidor MongoDB. Entre otras cosas podemos ver las conexiones/ desconexiones, errores, etc.

    2. Una vez instalado el producto, pasaremos a crear el servicio Windows MongoDB. Este servicio nos permitirá que el servidor de base de datos MongoDB se ponga en marcha automáticamente cada vez que reiniciemos el ordenador. 3. Para ello, primero crearemos la siguiente estructura de directorios desde una ventana CMD o, si se preere, desde un Explorador de Windows. C:\>mkdir mongodb\data\db mongodb\data\log

    4. A continuación, crearemos el chero C:\mongodb\data\mongodb.cfg con el siguiente código: systemLog: destination: le path: C:\mongodb\data\log\mongod.log storage: dbPath: C:\mongodb\data\db

    Este es el chero de conguración que se aplicará a nuestro servidor MongoDB. En él estamos indicando las carpetas y cheros que se usarán para los datos y cheros log. 5. Finalmente crearemos el servicio ejecutando el comando siguiente: C:\Program

    Files\mongodb\Server\3.4\bin>mongod.exe

    –cong

    c:\

    mongodb\data\mongodb.cfg –install

    Hay que tener en cuenta que debemos hacerlo como (botón derecho sobre el icono de “Símbolo del Sistema” [CMD] y pulsar “Ejecutar como ”) y que mongod.exe puede variar de ubicación según la versión que hubiéramos instalado en el paso 1. 6. Ahora pasaremos a vericar que se haya creado el servicio accediendo a la ventana “Servicios” de Windows desde el menú Windows o ejecutando services.msc desde CMD. Para poner en marcha el servicio podemos pulsar Iniciar desde esta misma ventana o hacerlo reiniciando el ordenador.

    El gran libro de Angular

    299

    7. En estos últimos apartados del ejercicio añadiremos el código necesario en nuestra aplicación MEAN para que realice la conexión al servidor de base de datos MongoDB. Primero instalaremos el módulo mongoose, que es la librería que usaremos para conectarnos a MongoDB: C:\Ej100_angular\071_ejMean>npm install –save mongoose

    8. Una vez terminada la instalación, abriremos nuestro proyecto con nuestro editor (Atom), y añadiremos el siguiente código en el archivo server.js: var mongoose = require(‘mongoose’); //////////////////////////////////////////////////////// // Conexión a la base de datos MongoDB a traves de Mongoose var dbURI = ‘mongodb://localhost/db_mean’; mongoose.connect(dbURI, {useMongoClient: true});

    300

    El gran libro de Angular

    // Conguracion de los eventos de la conexión Mongoose mongoose.connection.on(‘connected’, function () { console.log(‘Mongoose default connection open to ‘ + dbURI); }); mongoose.connection.on(‘error’,function (err) { console.log(‘Mongoose default connection error: ‘ + err); }); mongoose.connection.on(‘disconnected’, function () { console.log(‘Mongoose default connection disconnected’); }); // Si el proceso ‘Node’ termina, se cierra la conexión Mongoose process.on(‘SIGINT’, function() { mongoose.connection.close(function () { console.log(‘Mongoose default connection disconnected through app termination’); process.exit(0); }); }); //////////////////////////////////////////////////////// // Creamos la aplicacion express y la conguramos ...

    9. Con este código nuestro servidor realiza la conexión a la base de datos MongoDB y congura la gestión de eventos principales para interceptar las conexiones/desconexiones que se produzcan en la base de datos. 10. Finalmente ejecutaremos nuestra aplicación de la siguiente manera: C:\Ej100_angular\071_ejMean>node server.js

    Desde la propia ventana de CMD deberíamos ver el texto correspondiente al evento “connected”, que indicaría que la conexión se ha realizado correctamente.

    El gran libro de Angular

    301

    073

    MEAN: Creación de la API Restful (parte I)

    En este ejercicio construiremos la RESTful API de nuestra aplicación, implementando los casos CRUD (Create/Read/Update/Delete) para crear/ver/editar/borrar las “tareas” de nuestra base de datos. En la siguiente tabla se muestran los 5 endpoints que vamos a implementar y que denirán nuestra API:

    HTTP

    URL

    Descripción

    GET

    /api/tareas

    Devuelve todas las tareas

    POST

    /api/tareas

    Crea una tarea

    GET

    /api/tareas/:tareaId

    Devuelve una tarea

    PUT

    /api/tareas/:tareaId

    Modica una tarea

    DELETE

    /api/tareas/:tareaId

    Borra una tarea

    Para construir la API seguiremos el patrón de diseño MVC (Modelo-Vista-Controlador). MVC separa datos y lógica de negocio de una aplicación, respecto su interfaz de . Para ello, propone la construcción de estos tres componentes: •





    302

    Modelo: representa los datos y lógica de negocio de la aplicación. En nuestro caso, el modelo quedará representado por una entidad “Tarea” con las propiedades y métodos necesarios. Vista: elemento con el que interactúa el . En nuestro caso, al ser una API, el va a ser otro componente software y la vista van a ser los endpoints disponibles y los datos que devolvemos (archivos JSON). Controlador: hace de intermediario entre la vista y el modelo: pide datos al modelo para devolvérselos a la vista, y realiza acciones sobre el modelo cuyo origen se produce en la vista.

    El gran libro de Angular

    Importante Es importante que siempre usemos patrones de diseño, como el MVC (ModeloVista-Controlador) en nuestros desarrollos. Nos ayudan a estructurar los proyectos facilitando su desarrollo y mantenimiento.

    Vamos a empezar con el ejercicio: 1. Abriremos el proyecto 071_ejMean con el editor Atom y, en la raíz de nuestro proyecto, crearemos los directorios “server”, “server/controllers”, “server/models” y “server/routes”.

    2. A continuación, crearemos las rutas o endpoints de nuestra API. Para hacerlo, primero crearemos el chero tarea.js en la carpeta routes, y luego le añadiremos el siguiente código: server/routes/tarea.js module.exports = function(app){ var tareaCtrl = require(‘../controllers/tarea’); app.route(‘/api/tareas’) .get(tareaCtrl.list_all_tareas) .post(tareaCtrl.create_tarea); app.route(‘/api/tareas/:tareaId’) .get(tareaCtrl.read_tarea) .put(tareaCtrl.update_tarea) .delete(tareaCtrl.delete_tarea); }

    El gran libro de Angular

    303

    3. Seguidamente crearemos el controlador al que hacíamos referencia en el código anterior. Crearemos el chero tarea.js en la carpeta controller, y luego le añadiremos el siguiente código: server/controller/tarea.js exports.list_all_tareas = function(req, res) {res.send(‘ ’);}; exports.create_tarea

    =

    function(req,

    res)

    {res.send(‘Tarea

    creada’);}; exports.read_tarea = function(req, res) {res.send(‘ ’);}; exports.update_tarea modicada’);};

    =

    function(req,

    res)

    {res.send(‘Tarea

    exports.delete_tarea eliminada’);};

    =

    function(req,

    res)

    {res.send(‘Tarea

    De momento, las funciones de nuestro controlador únicamente devuelven un texto indicando la operativa realizada. En el siguiente capítulo completaremos este código. 4. Finalmente pondremos la carga de las rutas de la API en el código del servidor. Para ello, simplemente añadiremos el requerimiento de “server/ routes/tarea.js” en server.js: server.js //Cfg. de las rutas app.get(‘/api’, (req, res) => { res.send(‘La API funciona’); }); require(‘./server/routes/tarea’)(app); app.get(‘*’, (req, res) => { res.sendFile(path.(__dirname, ‘dist/index.html’)); });

    Es importante mantener el orden de líneas indicado, ya que el servidor resuelve las rutas de arriba abajo. Si pusiéramos la referencia “…/tarea” por debajo de la ruta “app.get(‘*’,…”, ninguna petición HTTP llegaría a nuestra API. 5. Una vez introducido todo el código, vamos a poner en marcha la aplicación para probar la API: C:\Ej100_angular\071_ejMean>node server.js

    304

    El gran libro de Angular

    6. Las peticiones HTTP de prueba las lanzaremos a través del software Postman. Postman funciona como una extensión de Google Chrome permitiendo construir y lanzar peticiones HTTP de forma muy sencilla. Con este software, podremos probar nuestra API sin tener que esperar al desarrollo de la aplicación Angular. Postman lo podemos descargar de forma gratuita desde www.getpostman.com, y su instalación es muy fácil e intuitiva. 7. A través de Postman lanzaremos peticiones HTTP para cada uno de los endpoint denidos, congurando método (get,…) y URL según el caso. Vea distintos ejemplos:

    El gran libro de Angular

    305

    306

    El gran libro de Angular

    El gran libro de Angular

    307

    074

    MEAN: Creación de la API Restful (parte II)

    En este ejercicio terminaremos la RESTful API de nuestra aplicación. El primer paso será crear el modelo de datos “Tarea” con los siguientes campos: titulo, creada (fecha creación) y estado (‘Por hacer’, ‘En progreso’, ‘Hecha’). Este modelo de datos lo crearemos usando Mongoose, de esta manera, el modelo dispondrá de forma automática de todos los métodos necesarios para trabajar con la base de datos MongoDB a la que nos habíamos conectado. Una vez hecho esto, completaremos el controlador “tarea”.

    Importante Las funciones de Mongoose pueden devolver todo tipo de avisos y errores (“id de registro inexistente”, etc.). Es importante gestionarlos e informar al de ellos.

    Vamos a empezar con el ejercicio: 1. Primero de todo abriremos el proyecto 071_ejMean con el editor Atom, y crearemos el modelo de datos “Tarea”. Para ello, crearemos el chero tarea.js en la carpeta models y le añadiremos el siguiente código: server/models/tarea.js var mongoose = require(‘mongoose’); var Schema = mongoose.Schema; var tareaSchema = new Schema({ titulo: { type: String, Required: ‘El campo titulo es obligatorio.’ }, fecha: { type: Date, default: Date.now }, estado: { type: [{ type: String, enum: [‘Por hacer’, ‘En progreso’, ‘Hecha’] }], default: [‘Por hacer’] } }); module.exports = mongoose.model(‘Tarea’, tareaSchema); 308

    El gran libro de Angular

    2. Seguidamente modicaremos las funciones del controlador “tarea” sustituyendo el envío de texto informativo por la operativa real sobre la base de datos. server/controllers/tarea.js

    var mongoose = require(‘mongoose’); var Tarea = require(‘../models/tarea’); exports.list_all_tareas = function(req, res) { Tarea.nd({}, function(err, tarea) { if (err) res.send(err); res.json(tarea); }); }; exports.create_tarea = function(req, res) { var new_tarea = new Tarea(req.body); new_tarea.save(function(err, tarea) { if (err) res.send(err); res.json(tarea); }); }; exports.read_tarea = function(req, res) { Tarea.ndById(req.params.tareaId, function(err, tarea) { if (err) res.send(err); res.json(tarea); }); }; exports.update_tarea = function(req, res) { Tarea.ndOneAndUpdate({_id: req.params.tareaId}, req.body, {new: true}, function(err, tarea) { if (err) res.send(err); res.json(tarea); }); }; exports.delete_tarea = function(req, res) { Tarea.remove({_id: req.params.tareaId}, function(err, tarea) { if (err) res.send(err); res.json({ message: ‘Tarea eliminada correctamente’ }); }); };

    El gran libro de Angular

    309

    Como se puede ver en el código, el objeto creado a partir del modelo “Tarea” ya dispone de todos los métodos necesarios para trabajar con la base de datos MongoDB y se usan según convenga. 3. Con esto ya habremos terminado nuestra API. Para probarla ejecutaremos nuestro servidor y haremos las pruebas con Postman. C:\Ej100_angular\071_ejMean>node server.js

    310

    El gran libro de Angular

    El gran libro de Angular

    311

    312

    El gran libro de Angular

    075

    MEAN: Desarrollo de componentes y rutas de la aplicación Angular

    Una vez terminado el backend de la aplicación, ahora trabajaremos en su frontend. Desarrollaremos la aplicación Angular que habíamos creado en el ejercicio 071 de esta serie. La aplicación mostrará una vista principal con las tareas de la base de datos, y una de secundaria para modicarlas y para crear nuevas tareas. Vamos a empezar con el ejercicio: 1. Primero de todo abriremos el proyecto 071_ ejMean con el editor Atom. 2. A continuación, pondremos en marcha la aplicación Angular. En estos primeros ejercicios no necesitaremos la API de servicios, por lo que de momento no pondremos en marcha la aplicación Express.

    Importante Es importante que organicemos adecuadamente el código en carpetas para facilitar su gestión. Si no lo hacemos correctamente, esta gestión puede complicarse en aplicaciones grandes. Consulte https:// angular.io/guide/ styleguide#folders-byfeature-structure para obtener más información.

    C:\Ej100_angular\071_ejMean>ng serve

    3. Seguidamente añadiremos los links de Bootstrap (https://v4-alpha. getbootstrap.com) en index.html para poder hacer uso de sus hojas de estilo. Consulte el ejercicio 087 para obtener más información. 4. Desde la línea de comandos crearemos los componentes tareaLista y editTarea. El primer componente será la vista principal de la aplicación y será donde visualizaremos la lista de tareas de la base de datos. Mientras que el segundo componente será la vista que utilizaremos para crear y modicar tareas.

    El gran libro de Angular

    313

    C:\Ej100_angular\071_ejMean>ng generate component tareaLista C:\Ej100_angular\071_ejMean>ng generate component editTarea

    5. Una vez creados los componentes, pasaremos a realizar la conguración del servicio Router para poder pasar de una vista a otra a través del URL. El primer paso será realizar la importación del servicio en “app.module.ts”: src/app/app.module.ts import { RouterModule, Routes } from ‘@angular/router’; …

    6. A continuación, realizaremos la conguración de rutas en el mismo chero. /tareas será nuestra ruta principal, y nos llevará al componente tareaLista. Para la modicación y creación de tareas tendremos las rutas “tareas/:id/ edit” (“:id” será el identicador de tarea) y “tareas/new”, respectivamente, que nos llevarán al componente editTarea. src/app/app.module.ts … const appRoutes: Routes= [ { path:’tareas’, component:TareaListaComponent}, { path:’tareas/:id/edit’, component:EditTareaComponent }, { path:’tareas/new’, component:EditTareaComponent }, { path:’**’, redirectTo:’/tareas’, pathMatch:’full’} ];

    @NgModule({ declarations: […], imports: […,RouterModule.forRoot(appRoutes)], …

    7. Finalmente pondremos la etiqueta “router-outlet” en el template del componente principal para indicar al servicio Router donde debe realizar las visualizaciones de los componentes.

    314

    El gran libro de Angular

    src/app/app.component.html

    Gestor de Tareas 5d4m1p



    8. Desde el navegador puede realizar las pruebas para validar el código. Para el URL “localhost:4200/”, será redireccionado a “localhost:4200/ tareas”, para el URL “localhost:4200/tareas” visualizara el componente tareaLista, para “localhost:4200/tareas/:id/edit” y “localhost:4200/tareas/ new” visualizará el componente editTarea, y para cualquier otra ruta será redireccionado a “localhost:4200/tareas”.

    9. Antes de empezar a desarrollar los componentes, crearemos varios elementos que estos necesitarán: modelo de datos, servicio de a la API del backend, etc. Para empezar, primero crearemos la carpeta shared dentro de “src/app”. En ella pondremos todos estos elementos compartidos por los componentes de la aplicación. La carpeta la crearemos pulsando botón derecho del ratón encima de la carpeta src/app, seleccionando “New Folder”, y deniendo la nueva carpeta como shared. El gran libro de Angular

    315

    10. El primer elemento compartido que crearemos será el modelo de datos “tarea”, que dará forma a la entidad gestionada por la aplicación, o sea, una tarea. Pulsaremos el botón derecho del ratón encima de la carpeta src/ app/shared, seleccionaremos “New File” y deniremos el nuevo chero como tarea.model.ts. El modelo de datos “tarea” lo deniremos con los mismos campos y tipos que habíamos utilizado en el backend: src/app/shared/tarea.model.ts type TareaEstados = “Por hacer” | “En progreso” | “Hecha”; export var TareaEstadosSelect = [{value: “Por hacer”}, {value: “En progreso”}, {value: “Hecha”}];

    export class TareaModel { constructor( public _id: string, public titulo: string, public fecha: Date, public estado: TareaEstados ) {} }

    316

    El gran libro de Angular

    076

    MEAN: Desarrollo de la operativa “Lectura de tareas”

    Continuado el desarrollo del frontend de nuestro “Gestor de Tareas”, en este ejercicio crearemos el servicio de a la API con una primera función para obtener las tareas de la base de datos, y desarrollaremos el componente tareaLista para que las muestre. Vamos a empezar con el ejercicio: 1. Primero de todo abriremos el proyecto 071_ejMean con el editor Atom. 2. Desde la línea de comandos crearemos el servicio “tarea” que nos dará a la API del backend. Este servicio lo crearemos dentro de la carpeta shared. C:\Ej100_angular\071_ejMean>ng generate service shared/tarea

    3. Para poder usar el servicio “tarea” (TareaService), deberemos registrar su proveedor. En este caso lo haremos a nivel de módulo para que todos sus componentes puedan usarlo. Por otra parte, “TareaService” utilizará el servicio de Angular HttpClient para realizar las peticiones HTTP a la API del backend. Por tanto, aprovecharemos la modicación en “app.module.ts” para añadir también la importación del módulo HttpClientModule. src/app/app.module.ts import {HttpClientModule} from ‘@angular/common/http’; import { TareaService } from ‘./shared/tarea.service’; … @NgModule({ declarations: […], imports: […, HttpClientModule], providers: [TareaService],…}) export class AppModule { }

    El gran libro de Angular

    317

    4. Seguidamente crearemos la primera función de TareaService: “getAllTareas()”. Esta función se utilizará para obtener todas las tareas de la base de datos. src/app/shared/tarea.service.ts … @Injectable() export class TareaService { constructor(private http: HttpClient) { } getAllTareas() { return this.http.get (‘http://localhost:3000/ api/tareas’); } }

    Fíjese que “getAllTareas()” devuelve un observable obtenido a partir de la ejecución de “HttpClient.get()” sobre el endpoint “get – ‘/api/ tareas’ – ‘Devuelve todas las tareas’” de nuestra API. La petición HTTP hacia la API se hará efectiva cuando se realice la subscripción sobre ese observable. Para más información consulte el capítulo 054.

    Importante La pipe async nos ahorra la suscripción y liberación de memoria (unsubscribe) explícitas que suelen hacerse al gestionar observables.

    5. Finalmente inyectaremos el servicio “tarea” al componente “tareaLista”, y modicaremos su código para que obtenga las tareas a través del servicio y las muestre por su template. src/app/tarea-lista/tarea-lista.component.ts … @Component({…}) export class TareaListaComponent implements OnInit { tareas: Observable ; constructor(private tareaService: TareaService) { } ngOnInit() { this.tareas = this.tareaService.getAllTareas(); } } src/app/tarea-lista/tarea-lista.component.html

    318

    El gran libro de Angular

    <eldset class=”form-group col-sm-11”> <eldset class=”form-group col-sm-1”>+
    … …
    Título
    {{tarea.titulo}}


    Fíjese que la subscripción al observable obtenido en “getAllTareas()” se realiza con la pipe async. 6. Para probar el código necesitaremos que la API esté en marcha. Por tanto, primero compilaremos la aplicación Angular mediante “ng build”, y seguidamente ejecutaremos la aplicación Express con “node server.js”. 7. Seguidamente, sitúese en http://localhost:3000 para que la aplicación Express le envíe la aplicación Angular al navegador. Enseguida debería ver las tareas que habíamos creado con Postman anteriormente.

    El gran libro de Angular

    319

    320

    El gran libro de Angular

    077

    MEAN: Desarrollo de las operativas “creación, modicación y eliminación de tareas” (parte I)

    Continuando el desarrollo del frontend de nuestro “Gestor de Tareas”, en este ejercicio trabajaremos con la implementación de las funcionalidades para crear, modicar y borrar tareas. Las acabaremos en el siguiente y último ejercicio de la serie. 1. Primero abriremos el proyecto 071_ejMean con el editor Atom. 2. Abriremos el template del componente tareaLista y conguraremos los botones de crear y modicar tareas. Esta conguración consistirá en añadir los links a las rutas “tareas/new” y “tareas/:id/edit” (“:id”: identicador de tarea), respectivamente. Las dos rutas nos llevaran al componente editTarea. Vea un ejemplo al pulsar la edición de una tarea.

    Importante Suele ser habitual la gestión de observables al llamar a servicios. Apóyese en los operadores RxJs para gestionar de forma efectiva todos estos observables, tal como hemos hecho aquí para cargar la tarea del componente editTarea.

    src/app/tarea-lista/tarea-lista.component.html … <eldset class=”form-group col-sm-1”> +Edit

    El gran libro de Angular

    321

    3. Antes de implementar el componente editTarea, vamos a añadir en el servicio “tarea” las distintas funciones para leer, crear y modicar una tarea de la base de datos. Cada una de ellas lanzará la petición HTTP que corresponda en cada caso. src/app/shared/tarea.service.ts … getTarea(id: string){ return this.http.get (‘http://localhost:3000/ api/tareas/’ + id); } addTarea(tarea: TareaModel){ return this.http.post (‘http://localhost:3000/ api/tareas’, { titulo: tarea.titulo, fecha: tarea.fecha, estado: tarea.estado}); } updateTarea(tarea: TareaModel){ return this.http.put (‘http://localhost:3000/ api/tareas/’ + tarea._id, { titulo: tarea.titulo, fecha: tarea. fecha, estado: tarea.estado}); } …

    4. También necesitaremos importar FormsModule en nuestra aplicación, ya que en el template editTarea implementaremos un formulario para la entrada de datos de la tarea que se vaya a crear o modicar. src/app/app.module.ts import { FormsModule }

    from ‘@angular/forms’;

    … @NgModule({ declarations: […], imports: […, FormsModule], …}) export class AppModule { }

    5. Ahora ya podemos empezar el desarrollo del componente editTarea. Primero crearemos una variable tarea que contendrá la tarea que estemos modicando o creando. En la función ngOnInit() inicializaremos su valor. Si el URL contiene el parámetro id. de tarea, la inicializaremos con la tarea que nos devuelva el backend para esa id.; en caso contrario, la inicializaremos 322

    El gran libro de Angular

    con una nueva. Estas llamadas devuelven observables y se gestionan mediante operadores de la librería RxJs. src/app/edit-tarea/edit-tarea.component.ts … @Component({…}) export class EditTareaComponent implements OnInit { tarea: TareaModel; tareaEstadosSelect = [];

    constructor(private route: ActivatedRoute, private router: Router, private tareaService: TareaService) { } ngOnInit() { this.tareaEstadosSelect = TareaEstadosSelect;

    this.route.paramMap .map(params => params.get(‘id’)) .switchMap(id => { if (id) return this.tareaService.getTarea(id); else return Observable.of(new TareaModel(null,””,new Date(), “Por hacer”)); }) .subscribe(tarea => {this.tarea = tarea; console. log(tarea);}, error => {console.log(error)}); } }

    El gran libro de Angular

    323

    6. Finalmente, crearemos la función onSubmit() para guardar los datos. Si la tarea tiene identicador, se llamará a la función de modicación del servicio y, en caso contrario, a la de creación. Posteriormente, vincularemos onSubmit() al formulario del template del componente. src/app/edit-tarea/edit-tarea.component.ts … onSubmit(){ if (this.tarea._id) this.tareaService.updateTarea(this.tarea) .subscribe(data => {console.log(data); this.router. navigate([‘/tareas’]);},error=>console.log(error)); else this.tareaService.addTarea(this.tarea) .subscribe(data => {console.log(data); this.router. navigate([‘/tareas’]);},error=>console.log(error)); } }

    324

    El gran libro de Angular

    078

    MEAN: Desarrollo de las operativas “creación, modicación y eliminación de tareas” (parte II)

    En este ejercicio acabaremos el “Gestor de Tareas” que hemos estado desarrollando durante esta serie de ejercicios. 1. Primero abriremos el proyecto 071_ejMean con el editor Atom. 2. Seguidamente abriremos el template del componente editTarea, y le añadiremos el código para que visualice un formulario con los distintos campos de la tarea que tenga cargada (mire el anterior ejercicio para obtener más información).

    Importante A modo de práctica le proponemos añadir nuevos campos asociados a las tareas. También puede practicar con la librería HttpClient añadiendo un interceptor de mensajes para monitorizar el traco de la aplicación con su backend.

    src/app/edit-tarea/edit-tarea.component.html
    <eldset class=”form-group”>
    <eldset class=”form-group”>
    El gran libro de Angular

    325

    <eldset class=”form-group”>
    <eldset class=”form-group”>


    También hemos congurado el botón para guardar los datos. Este botón solamente estará activo si los datos son válidos, y al pulsarlo se llamará la función onSubmit() del componente. 3. En el formulario hemos indicado que todos los campos son obligatorios (“required”). Para indicar al este requerimiento, vamos tocar la hoja de estilo del componente para que los campos obligatorios vacíos queden en rojo y si no en verde. src/app/edit-tarea/edit-tarea.component.css .ng-valid[required], .ng-valid.required

    { border-left: 5px

    solid #42A948; /* green */} .ng-invalid:not(form) */}

    326

    El gran libro de Angular

    { border-left: 5px solid #a94442; /* red

    4. Finalmente implementaremos la funcionalidad para borrar tareas. Primero añadiremos la función en el servicio tarea: src/app/shared/tarea.service.ts deleteTarea(id: string){ return this.http.delete<string>(‘http://localhost:3000/api/ tareas/’ + id); }

    5. Y por último codicaremos el botón borrar del template de tareaLista para que llame a la función deleteTarea(id) que implementaremos en el componente. src/app/tarea-lista/tarea-lista.component.ts …. deleteTarea(id:string) { this.tareaService.deleteTarea(id) .subscribe(data=>console.log(data),error=>console. log(error)); this.tareas = this.tareaService.getAllTareas(); } …

    src/app/tarea-lista/tarea-lista.component.html -

    6. Para probar el código recuerde ejecutar la aplicación Express con su API. Por tanto, primero compilaremos la aplicación Angular mediante “ng build”, y seguidamente ejecutaremos la aplicación Express con “node server.js”. Luego sitúese en http://localhost:3000 para probar la aplicación. 7. Pruebe las distintas funcionalidades implementadas. Por ejemplo, puede crear una nueva tarea, visualizarla en el listado, y editarla para cambiar su estado.

    El gran libro de Angular

    327

    328

    El gran libro de Angular

    079

    CSS: Introducción (parte 1)

    Queda fuera del alcance de este libro la realización de un curso de CSS, pero hemos considerado oportuno incluir un par de ejercicios para familiarizarnos con este lenguaje prácticamente imprescindible en la programación web de hoy en día. CSS es un lenguaje de estilo que dene la presentación de los documentos HTML y las siglas que le dan nombre son el acrónimo de CascadingStyle Sheets (hojas de estilo en cascada).

    Importante Use CSS para dar estilo a sus páginas HTML y dena todo en un archivo externo para facilitar el mantenimiento del mismo y de las páginas que lo utilicen.

    Entre los diversos benecios obtenidos por el uso de CSS, se halla el de poder concentrar todas las deniciones previstas para los distintos elementos que componen nuestras páginas en un solo archivo de estilos de forma que podemos variar el aspecto de cientos de documentos muy rápidamente solo modicando dicho archivo de estilos. La sintaxis básica es: selector { propiedad: valor }, donde: • • •

    selector: elemento HTML al que se aplica la propiedad (p. ej.,

    ), propiedad: propiedad que queremos modicar (p. ej., ‘color’), valor: valor de la propiedad (p. ej., ‘red’).

    Las formas de aplicar CSS a un documento son las siguientes: • • •

    Directamente a una etiqueta. Usando la etiqueta style y denirla en el apartado head de nuestra página. Usando un chero de estilos con la extensión css y referenciándolo en nuestra página. Este es el método más recomendado, ya que es una de las características que más potencia da al lenguaje.

    En el siguiente ejercicio vamos a probar algunas de las propiedades relacionadas con colores, fuentes y textos.

    El gran libro de Angular

    329

    1. En primer lugar, nos situaremos en la carpeta C:\Ej100_angular y crearemos una carpeta denominada 079_CSS_Intro1 para desarrollar este ejercicio. 2. Dentro de la misma, crearemos dos archivos: MiPagina.html y estilos.css. 3. MiPagina.html contendrá inicialmente lo siguiente:

    Mi pagina 286d44

    Pagina de pruebas 1w426e



    330

    El gran libro de Angular

    El chero de estilos contendrá una denición de color para

    y otra de color de fondo para el de la siguiente manera: h1 { color: #2E64FE; } body { background-color: #58FAAC; } Si visualizamos la página en nuestro navegador veremos cómo, efectivamente, nuestro 2i4l67

    se muestra en color azul sobre un fondo verde . 4. Ahora, en la misma carpeta insertaremos una imagen cualquiera (p. ej., img1.jpg) la cual usaremos como imagen de fondo para de la siguiente manera: body { background-color: #58FAAC; background-image: url(“img1.jpg”); background-repeat: no-repeat; } El gran libro de Angular 331 Haga diversas pruebas cambiando no-repeat por repeat-x, repeat-y repeat. 5. Añadimos a las siguientes instrucciones para colocar la imagen en la esquina inferior derecha y hacer que siempre se muestre en esa posición, aunque en la ventana se produzca un scroll: background-position: right bottom; background-attachment: xed; A continuación, añadiremos algunas propiedades relacionadas con las fuentes, incluyendo los siguientes estilos para 2f6y1j

    y 1y4t6m

    en estilos.css: h2 { color: red; font-variant: small-caps; font-family: arial, verdana, sans-serif; font-weight: bold; } h3 { color: yellow; font-style: italic; font-size: 120%; } 332 El gran libro de Angular En la página HTML incluya las etiquetas 5p394t

    y 1y4t6m

    detrás de 5w4uj

    :

    Pagina de pruebas 1w426e

    Segundo titulo 1p5b5p

    Tercer titulo 3c65o



    Guarde los archivos y refresque la página en el navegador. 6. Por último, vamos a probar algunas propiedades relacionadas con el texto. Para ello, incluiremos los siguientes estilos al nal del archivo estilos.css: p { text-decoration: underline; letter-spacing: 6px; text-transform: uppercase; }

    En la página HTML incluimos un párrafo detrás de con los siguiente:

    Es un parrafo



    Gracias al estilo, observaremos que el texto del párrafo aparece subrayado, con una separación de 6 píxeles entre cada carácter y todo en mayúsculas. El gran libro de Angular

    333

    334

    El gran libro de Angular

    080

    CSS: Introducción (parte 2)

    En este segundo ejercicio dedicado a CSS, vamos a ver algunos ejemplos más, relacionados con la forma de mostrar enlaces, identicar elementos, crear cajas, listas, usar bordes, posicionamiento de elementos, etc.

    Importante Puede aplicar diversas clases a un mismo elemento para combinar estilos y también puede realizar deniciones aplicables a diversos elementos y combinaciones entre elementos, estados e identicadores.

    A la hora de denir estilos en un archivo .css, podemos hacerlo referenciando los selectores convencionales o bien referirnos a clases (class), pseudo-clases (o estado de elementos), identicadores (id) o una combinación de todos ellos. Por ejemplo, para asignar un color de fuente de color rojo, podríamos hacerlo a:

    Elemento

    Comentario

    Ejemplo

    selector

    , 275q3y

    ,

    ,<span>, etc.

    span {color: blue;}

    class

    Un nombre de clase añadida a un selector mediante class=”miClase”

    .miClase { color: blue;}

    a:visited

    Un link que ya ha sido visitado

    a:visited {color: red;}

    #miId

    Un identicador determinado

    #miId {color: red;}

    selector:estado. Un selector con un estado y una clase clase

    div:hover.impares

    selector:estado. Un selector con un estado y un identicador id

    div:hover#dos {color: red;}

    Selector1, selec- Un selector u otro tor2, …

    span, h1 {color: red;}

    {color:

    red;}

    El gran libro de Angular

    335

    1. En primer lugar, nos situaremos en la carpeta C:\Ej100_angular y crearemos la carpeta denominada 080_CSS_Intro2 para desarrollar este ejercicio. Dentro de la misma, crearemos dos archivos: MiPagina.html y estilos.css. 2. MiPagina.html contendrá un par de enlaces y un párrafo que incluye una etiqueta span. span básicamente es un contenedor genérico que nos permitirá asignar estilos a partes de una página.

    3. estilos.css contendrá una denición de color para

    y otra de color de fondo para el . 4. Podemos observar que 2s5353

    contiene diversas deniciones y no todas tienen por qué estar agrupadas (hay 2 líneas referidas a 4j3w3o

    ). Veremos que esto facilita el hecho de que una misma denición de estilo pueda aplicarse a diferentes tags o elementos. 5. Guardamos los archivos y visualizamos la página en el navegador para ver cómo queda. 6. A continuación, vamos a utilizar el concepto de pseudo-clase que, en denitiva, se trata de una palabra clave que añadimos a los selectores para 336 El gran libro de Angular poder especicar el estado de un elemento. Por ejemplo, podríamos distinguir entre los enlaces no visitados (link), los visitados (visited) o detectar cuando pasamos el puntero del ratón sobre un enlace (hover). En nuestro caso, añadiremos al nal de nuestro chero estilos. css una denición para cada estado. 7. Si guardamos la página y la visualizamos en el navegador, vemos que los links no visitados (link) aparecen en verde, si pasamos el puntero del ratón sobre el link de Google (hover) el texto cambia de tamaño y de color y si pulsamos sobre el link de Google y regresamos de nuevo a la página, ahora veremos que el link visitado (visited) aparece en rojo. 8. Ahora, añadiremos una denición para mostrar en color azul el texto contenido la apertura y cierre de span. Para ello, podemos hacer una denición exclusiva para span o bien aprovechar la que ya hicimos para h1 simplemente añadiendo la palabra span al inicio de la denición y una coma antes de h1. 9. Podemos comprobar cómo queda en la página. El gran libro de Angular 337 10. A continuación, vamos a añadir otro párrafo ( 1q2j5q

    ) y 3

    sobre los que añadiremos algunos estilos.

    11. En primer lugar, haremos una denición genérica para los div incluyendo en estilos.css algunos estilos.

    12. Guarde los archivos y compruebe cómo queda en el navegador. Recuerde que margin dene el espacio alrededor del elemento y padding dene el espacio entre el borde y el elemento. Compruebe también el ancho, estilo y color del borde además del tamaño de la fuente.

    338

    El gran libro de Angular

    13. En css haremos una denición para una clase denominada especial (.especial) y otra denición para el identicador (#dos).

    14. Añadimos las clases y el identicador a nuestro párrafo nuevo y a los div impares dentro del archivo HTML.

    15. Veamos en el navegador cómo queda. Observe que, al redimensionar la página, el div con identicador dos se reposiciona dentro de la página.

    16. Por último, añadiremos un par de deniciones para ver cómo se pueden combinar elementos, estados e identicadores. 17. En un caso, estamos deniendo que, al pasar el ratón por encima de un
    que posea la clase especial o al pasar el ratón sobre el título

    , cambie el aspecto del bloque. Por otra, el aspecto cambiará al pasar sobre el bloque cuyo identicador es dos. El gran libro de Angular 339 340 El gran libro de Angular 081 HTML Es el lenguaje utilizado en Internet para fabricar páginas web. Tal y como sus propias siglas indican, se trata de un lenguaje “de marcado” (HyperText Markup Language) basado en una serie de etiquetas interpretadas por los navegadores para dar formato a las páginas. Además de texto, permite denir imágenes, vídeos, sonidos, juegos, etc. Para su edición, puede utilizarse cualquier editor de texto (p. ej., Bloc de notas) y los archivos que se generen han de tener generalmente la extensión html (aunque pueden usar otras como htm, etc.). Las etiquetas utilizadas están rodeadas por los símbolos < , > y representan un elemento. Los elementos a su vez poseen dos propiedades fundamentales: sus atributos y su contenido. Importante HTML es un lenguaje muy extendido y útil ya que, gracias al mismo, puede representarse el mismo contenido en cualquier plataforma y sistema que posea un navegador. Le invitamos a que profundice en el lenguaje para contar con más recursos a la hora de diseñar sus aplicaciones. En general, todos los elementos tienen una etiqueta (o tag) de apertura y otra de cierre que es la misma, pero anteponiendo al nombre del elemento, una barra (‘/’). A continuación, mostramos uno de los elementos más comunes como es el párrafo: 183943

    Ejemplo de párrafo



    Un ejemplo de estructura básica de un documento HTML donde pudiéramos incluir el párrafo de ejemplo anterior está compuesto por el siguiente código: Título de la página j4x5t

    Ejemplo de párrafo



    El gran libro de Angular

    341

    Podemos observar que el documento está encerrado entre los tags y en su interior contiene esencialmente un y un . dene la cabecera del documento y puede contener otros elementos relacionados con el estilo de la página o metadatos que aportan información sobre el autor u otros. es la parte donde se dene realmente el contenido y se muestra en los navegadores. Dentro de este apartado es donde se incluyen las etiquetas con las que fabricaremos nuestras páginas web. En nuestro navegador solo veremos el párrafo y el título de la página. No podemos relacionar todas las etiquetas que pueden utilizarse, ya que nos extenderíamos mucho más allá de lo que pretendemos en este ejercicio, pero de forma muy esquemática relacionamos a continuación las etiquetas más comunes:

    Etiqueta

    Comentario



    Dene el documento de tipo HTML.

    <br / 42416 <br /> Especica el título del documento.<br /> <br /> <style><br /> <br /> Permite indicar información de estilo.<br /> <br /> <body><br /> <br /> Contiene el cuerpo del documento.<br /> <br /> <h1><h2><h3><h4><h5><br /> <br /> Encabezados (nivel de 1 a 5).<br /> <br /> <p><br /> <br /> Párrafo.<br /> <br /> <hr><br /> <br /> Incluye línea de separación.<br /> <br /> <pre><br /> <br /> Texto preformateado que mantiene el texto tal y como está en el archivo.<br /> <br /> <ul><br /> <br /> Lista no ordenada.<br /> <br /> <li><br /> <br /> Elemento de una lista.<br /> <br /> <div><br /> <br /> Contenedor para bloques de texto.<br /> <br /> <a><br /> <br /> Dene hipervínculos.<br /> <br /> <i><br /> <br /> Muestra texto en itálica.<br /> <br /> 342<br /> <br /> El gran libro de Angular<br /> <br /> <b><br /> <br /> Muestra texto en negrita (bold).<br /> <br /> <br><br /> <br /> Introduce un salto de línea.<br /> <br /> <img><br /> <br /> Inserta una imagen.<br /> <br /> <object><br /> <br /> Permite insertar aplicaciones.<br /> <br /> <table><br /> <br /> Dene una tabla.<br /> <br /> <tr><br /> <br /> Dene una la de la tabla.<br /> <br /> <td><br /> <br /> Dene una columna dentro de una tabla.<br /> <br /> <form><br /> <br /> Dene un formulario (vea capítulo dedicado a forms dentro de este libro).<br /> <br /> <script><br /> <br /> Permite insertar programas.<br /> <br /> En el siguiente ejercicio, vamos a elaborar una página HTML con algunos ejemplos de las etiquetas más importantes usadas en este lenguaje. 1. En primer lugar, nos ubicaremos en Ej100_angular y crearemos la carpeta 081_HTML tecleando lo siguiente: C:\Ej100_angular>mkdir 081_HTML<br /> <br /> Dentro de la carpeta, crearemos un archivo llamado MiPagina.html con el siguiente contenido:<br /> <br /> El gran libro de Angular<br /> <br /> 343<br /> <br /> <!DOCTYPE html> <html> <head> <title>
    Etiqueta Ejemplo
    <p>

    Ejemplo de párrafo



    En la página, hemos creado una tabla para ir depositando los ejemplos que vayamos insertando (<) y (>) son los caracteres de ‘<’ y ‘>’, respectivamente, que han de indicarse así para evitar que HTML los interprete como caracteres especiales del lenguaje. Guarde la página y ábrala en el navegador. 2. A partir de aquí, pruebe de incorporar más etiquetas para hacer prácticas. Por ejemplo, trate de incorporar una la para cada una de las siguientes etiquetas

    , <pre>, y , , y e . Para el ejemplo de img, tendrá que copiar una imagen en la carpeta que ha creado para este ejercicio y llamarla img1.jpg. 3. Compruebe cómo queda la página con los ejemplos anteriores. 344 El gran libro de Angular El gran libro de Angular 345 082 JSON JSON (JavaScript Object Notation) es un formato de intercambio de datos bastante ligero que puede ser tratado por casi todos los lenguajes de programación. Es una alternativa a XML y existen multitud de utilidades que convierten ambos formatos entre sí. Se dene dentro del estándar de lenguaje de programación ECMAScript (ECMA). Básicamente, JSON posee dos estructuras: • • Importante JSON es un formato cada vez más extendido y que permite aligerar el intercambio de información entre multitud de lenguajes de programación y entornos. Una colección de pares de nombre/valor: objeto (o registro, estructura, etc.). Una lista ordenada de valores: vectores o listas. Puede representar los siguientes tipos de datos primitivos: cadenas de texto, números, booleanos y valores nulos. También es posible denir dos tipos de datos estructurados: objetos y arreglos. Cada pareja atributo/valor se dene de la siguiente manera: “nombre”: “Juanto” En este caso, el atributo es “nombre” y el valor “Juanto”. Los atributos siempre se encierran entre comillas (“). Los valores también excepto los numéricos que van sin comillas. Los objetos se encierran entre llaves de la siguiente manera: { “codigo”: 1, “nombre”: “Juanto” } Vemos que cada pareja atributo/valor se separa de la anterior por una coma (,). Los arreglos se encierran entre corchetes [] y separan sus valores entre comas. Por ejemplo, si denimos el atributo “aciones” con varios valores, podemos usar un arreglo de la siguiente forma: 346 El gran libro de Angular “aciones”: [“Leer”, “Escribir”, “Musica”] Los valores pueden ser valores simples o también objetos que a su vez pueden contener objetos y así sucesivamente. Por ejemplo, podríamos denir el objeto personas como un conjunto de objetos de la siguiente manera: { “personas”: [ { “codigo”: 1, “nombre”: “Juanto” }, { “codigo”: 2, “nombre”: “Miquel” }, { “codigo”: 3, “nombre”: “Andres” } ] } Existen muchas utilidades que nos permiten tratar archivos JSON validando su formato, convirtiéndolo a XML, exportándolo a otros formatos como CSV, normalizando su indentación, etc. Por ejemplo, puede usar un validador en línea llamado JSONLint en el siguiente URL: https://jsonlint.com/. Si acude a dicha página e introduce el código anterior en la caja de texto preparada a tal efecto y pulsa sobre el botón Validate JSON podrá comprobar si la estructura es correcta o no. Podemos utilizar también visores para inspeccionar los datos y navegar por ellos como, por ejemplo: http://jsonviewer.stack.hu/. Si accede a esta página y copia el contenido del ejemplo anterior, puede pulsar en la pestaña Viewer para ver la jerarquía de la información y navegar por ella. El gran libro de Angular 347 Por último, mostraremos otra utilidad muy completa (Code Beautify) que permite diferentes acciones que pueden resultar muy interesantes como, por ejemplo, validar, normalizar, convertir, exportar, editar código JSON, etc. Puede encontrar esta utilidad en https://codebeautify.org/jsonviewer. Por favor, introduzca el código anterior en esta utilidad y pruebe alguna de sus funcionalidades como, por ejemplo, la de Tree Viewer para ver la estructura de forma jerárquica y poder navegar por la misma, Minify para reducir el tamaño al máximo o JSON to XML para convertir un archivo JSON a XML. En el siguiente ejercicio, vamos a fabricar una pequeña aplicación que simplemente nos permita mostrar en el navegador y también en su consola cómo podemos crear, acceder y mostrar alguno de los valores de una estructura JSON. 1. En primer lugar, nos ubicaremos en Ej100_angular y crearemos el proyecto tecleando ng new intJSON. 348 El gran libro de Angular 2. Seguidamente, renombraremos el proyecto ubicándonos en Ej100_angular, y escribiendo lo siguiente: C:\Ej100_angular>rename intJSON 082_intJSON A continuación, abrimos el proyecto con nuestro editor y modicamos la clase AppComponent del chero app.component.ts para cambiar el título por defecto y añadir algunas deniciones de objetos de JSON. 3. Podemos ver que hemos creado un objeto persona con 3 atributos (codigo, nombre y aciones) y en el caso de aciones, hemos creado un arreglo con las diferentes aciones que posee esa persona. Podemos ver también que se ha creado un array de personas que incluye tres objetos persona cada uno de los cuales solo tiene codigo y nombre. 4. A continuación, vamos a denir en nuestro archivo styles.css algunos estilos para mejorar la presentación. 5. Ahora, modicaremos el archivo app.component.html para modicar el contenido que posee por defecto y mostrar los objetos que contienen JSON. Tras el título, insertaremos un primer bloque para mostrar el objeto persona en formato JSON y también, cada uno de sus atributos y valores. 6. Seguidamente y detrás del bloque anterior, añadimos el objeto array de personas también en formato JSON y luego, cada una de las personas en formato JSON. El gran libro de Angular 349 7. En el último bloque que añadiremos a continuación del anterior, y mediante *ngFor, recorremos el array de personas y mostramos por separado cada una de las mismas con sus atributos y valores. 8. Guardamos todo y arrancamos la aplicación en el navegador para ver la información de cada bloque. 9. En app.component.ts podemos añadir el método ngOnInit() para mostrar por la consola la información de los objetos de forma parecida a como lo hemos hecho en HTML. Lo añadiremos detrás de la denición de personas y antes del cierre de la clase AppComponent. Deniremos la función con un conjunto de llamadas a console.log para mostrar la información de diversas formas. Observe que en ngOnInit() hemos usado JSON.parse para crear un nuevo objeto, y que 350 El gran libro de Angular usamos también JSON.stringify para elaborar un string con el contenido del objeto tratado. 10. Abra el navegador (p. ej., en Google Chrome con CTRL+ MAYUS + I) y analice las salidas por la consola. Vea cómo al mostrar el objeto personas al nal de todo es posible desplegarlo pulsando sobre las echas que lo acompañan para ver su estructura. El gran libro de Angular 351 083 Google: Herramientas de desarrollador Las herramientas para desarrolladores nos permiten analizar diferentes aspectos de nuestra aplicación web como son el rendimiento, su composición, el uso de memoria, etc. Por ejemplo, Google Chrome (CTRL+MAYUS+I), Internet Explorer (F12), Mozilla Firefox (CTRL+MAYUS+I) ofrecen un menú similar para realizar las mismas acciones. A continuación, tomando como ejemplo Google Chrome, comentamos brevemente cada una de estas opciones. Opción Importante Utilice las herramientas de desarrolladores para depurar programas y visualizar mensajes por la Console, por ejemplo, para mostrar fácilmente el contenido de una variable o el paso por un método. Comentario Permite seleccionar un elemento de la página (CTRL+MAYUS+C). Simula la visualización de nuestra aplicación en un dispositivo (CTRL+MAYUS+M). Elements Permite analizar el estado del elemento HTML o CSS seleccionado y, además, es posible editarlo. Para deshacer cambios basta con pulsar CTRL+Z. Console Permite ver los mensajes de error y advertencias y también es muy útil si usamos console.log(“texto”) en nuestros métodos para realizar alguna traza. Sources Permite abrir cualquier componente de la web ofreciendo una estructura jerárquica y en árbol de los mismos y también permite depurar. Network Muestra el Network donde visualiza información sobre el rendimiento y actividad de red. Performance Muestra el TimeLine para analizar la actividad en tiempo de ejecución. 352 El gran libro de Angular Memory Muestra el Proles y permite analizar el tiempo de ejecución y uso de memoria. Application istra almacenamiento y BBDD. Security Muestra el Security, que permite depurar problemas con nuestro certicado y otros. Analiza la seguridad general de una página. Audits Muestra el Audit, que analiza la página cuando se carga y ofrece sugerencias para mejorar su rendimiento. Augury Permite depurar aplicaciones y visualizar la aplicación mediante herramientas grácas. En el siguiente ejercicio, mostraremos algunas de las funcionalidades para que podamos ver cómo acceder y manejar las opciones del menú de herramientas de Google Chrome. Podríamos utilizar cualquier página web, pero, en nuestro caso, nos basaremos en la aplicación realizada en el ejercicio 028 dirNgStyle al que añadiremos un bloque de salidas por Console. 1. Abrimos el ejercicio con nuestro editor (p. ej., Atom) y añadimos el siguiente bloque en app.component.ts detrás de la clase AppComponent: deneEstilos(){ ... return styles; } ngAfterContentChecked(){ console.log(“--------------------------- “); console.log(“hayLetraGrande “,this.hayLetraGrande); console.log(“hayColorFondo “,this.hayColorFondo); console.log(“hayLetraColor “,this.hayLetraColor); console.log(“hayLetraItalica “,this.hayLetraItalica); console.log(“--------------------------- “); } Seguidamente nos ubicamos en C:\Ej100_angular\028_dirNgStyle y arrancamos la aplicación tecleando ng serve. El gran libro de Angular 353 2. Abrimos el navegador y tecleamos el URL http://localhost:4200 para acceder a nuestra aplicación. 3. Accedemos a las herramientas de desarrolladores pulsando CTRL+MAYUS+I. 4. Si pulsamos sobre los checks Tamaño y Color, veremos que las variables hayLetraGrande y hayLetraColor pasan a valer true. 354 El gran libro de Angular 5. Podemos jugar un poco sobre la pestaña de Console pulsando sobre el icono ( ) y limpiando el contenido de la misma. Introducimos un ltro (p. ej., color) para mostrar solo aquellos mensajes que contengan dicho texto. Pulsamos sobre el botón Console settings ( ) para mostrar más opciones y marcar Show timestamps para añadir la hora a cada mensaje. Podemos realizar un sencillo cálculo mediante la función eval (p. ej., eval(2*3+4)) en el prompt (>) de la Console. 6. A continuación, seleccionaremos la opción Elements y observaremos que muestra el código fuente de la página además de información sobre sus estilos, eventos, breakpoints y propiedades. 7. Tecleamos CTRL+MAYUS+C (o pulsamos sobre el icono ) y seleccionamos el bloque inferior que contiene ‘Texto’. En la parte inferior derecha de la ventana, veremos que hay una serie de rectángulos contenidos entre sí que al pasar el puntero del ratón por encima de los mismos van resaltando en la página el aspecto asociado a cada rectángulo (position, margin, border, padding y contenido). El gran libro de Angular 355 8. Podemos observar también que en la parte superior izquierda aparece destacada la etiqueta div, en la que se muestra entre otras propiedades: el estilo, el color de fondo, el tamaño, etc. Si marcamos los checks Tamaño, Fondo y Color, observaremos cómo cambian los valores dentro de cada propiedad correspondiente. 9. Para acabar, podríamos simular la visualización de nuestra aplicación en un dispositivo móvil pulsando CTRL+MAYUS+M o bien pulsando sobre el botón ( ). 356 El gran libro de Angular 084 Control de versiones Git: Instalación, conguración y uso Git es un sistema de control de versiones libre y de código abierto. Como todo sistema de control de versiones, Git registra los cambios realizados sobre un archivo o conjunto de archivos a lo largo del tiempo, de manera que se puedan recuperar versiones especícas cuando sea necesario. Además, Git es fácil de usar, rápido, eciente y el editor Atom le da soporte. Por todo ello hemos pensado que sería interesante incluir este capítulo en el libro para ver sus conceptos de uso básicos. Los fundamentos básicos de Git son los siguientes: • • • Importante Git es un sistema de control de versiones distribuido, libre, de código abierto, fácil de usar, rápido, eciente y con soporte para la mayoría de editores como Atom o VisualCode de Microsoft. Es un sistema de control de versiones distribuido. Los clientes replican completamente el repositorio de versiones de un servidor central. A posteriori esto permite a los clientes realizar casi todas las operaciones de forma local evitando problemas de red. Además, se mejora la seguridad en el sentido de que si el servidor central falla, siempre es posible recuperar el repositorio a partir de cualquier cliente. Un proyecto Git tiene tres partes principales: el directorio Git con el repositorio de versiones y otros elementos de Git, el directorio de trabajo con una copia de una versión del proyecto sacada del directorio Git para su uso y modicación, y el área de preparación, un archivo del directorio Git con los cheros modicados preparados para la próxima conrmación (commit). Los cheros del directorio de trabajo pueden estar bajo seguimiento (tracked) o sin seguimiento (untracked) por parte de Git, como sería el caso de los cheros nuevos acabados de crear. Los cheros bajo seguimiento (tracked) pueden estar sin modicar, modicados o preparados (staged). El ujo general de trabajo consistiría en modicar archivos del directorio de trabajo, prepararlos para que se incluyan en la próxima conrmación (commit) y nalmente realizar la conrmación (commit) para guardar los cambios en el repositorio. Para empezar a usar Git, el primer paso será instalarlo. Para ello nos desplazaremos https://git-for-windows.github.io/, y descargaremos el instalador para Windows. Luego lo ejecutaremos seleccionando todas las opciones por defecto. Una vez El gran libro de Angular 357 instalado, tendremos tanto la versión de línea de comandos como la interfaz gráca de estándar. Seguidamente pasaremos a congurar un nombre de y email. Esta información es importante porque Git la utiliza y vincula a las conrmaciones (commit) que realicemos. Congúrelo indicando sus propios datos: C:\>git cong --global .name “Miquel” C:\>git cong --global .email [email protected] Ejecutando “git cong –list” puede conrmar la conguración. Vamos a seguir practicando con Git en un proyecto Angular: 1. Nos ubicaremos en ej100_angular, y crearemos el proyecto tecleando ng new testGit. Seguidamente lo renombraremos para que haga referencia a nuestro número de ejercicio ejecutando rename testGit 084_testGit, y nalmente lo abriremos con Atom. 2. Atom da soporte Git para la mayoría de operativas más comunes, pero para las más especializadas es probable que necesitemos usar la versión Git de línea de comandos. Para visualizar la ventana Git de Atom, seleccionaremos la opción “Packages/GitHub/Toggle Git Tab” del menú. 3. Para usar Git en el nuevo proyecto, primero deberemos crear su repositorio de versiones. Esto lo haremos desde la ventana Git de Atom seleccionando la opción “Create repository” e indicando que lo cree en C:\Ej100_angular\084_testGit. Con esta acción crearemos el subdirectorio Git (“.git”) con el repositorio. 4. En este momento, todos los cheros del proyecto están sin seguimiento (untracked). Aparecen todos en “Unstaged Changes” con un icono verde. Sin embargo, si se ja bien, realmente no aparecen todos. Por ejemplo, no aparecen los cheros descargados con npm (directorio/node_modules) 358 El gran libro de Angular para los que no tiene sentido realizar ningún seguimiento. Esto es así gracias a las excepciones indicadas en el archivo .gitignore que se creó de forma automática al crear el proyecto con “ng new…”. 5. Para empezar a controlar sus versiones, primero deberemos ponerlos bajo seguimiento (tracked). Para ello tendremos que hacer una conrmación inicial con todos ellos: pulsaremos la opción “Stage All”, pondremos nombre al commit, por ejemplo, “version inicial”, y pulsaremos “Commit”. 6. Ahora los cheros están bajo seguimiento (tracked) de Git. Si realiza una modicación, por ejemplo, en el chero src/app/app. component.ts, este chero pasará a estado modicado y aparecerá en “Unstaged Changes” con un icono amarillo distinto al que veíamos en el punto 4. A partir de aquí, puede realizar todo tipo de acciones desde esta misma ventana: a. Para un chero modicado, puede hacer clic para ver los cambios respecto su última conrmación, puede hacer doble clic para ponerlo en estado preparado (staged), o también puede deshacer los cambios desde el menú contextual (clic derecho) del chero. b. Puede deshacer la preparación (staged) de un chero con un clic. c. Puede crear una nueva conrmación (commit) con los cheros preparados (staged). El gran libro de Angular 359 La mejor forma de ver el histórico de conrmaciones realizadas es hacerlo a través de la aplicación “Git GUI”, o sea, la versión Git con interfaz gráca incluida en la instalación. Para ello ejecute “Git GUI”, abra el repositorio C:\Ej100_angular\084_testGit, y seleccione la opción “Repository/Visualize master’s History”. Tendrá una vista similar al de la imagen. Por último, comentar que podemos trabajar con repositorios remotos para facilitar la colaboración en un proyecto Git. Veamos, brevemente, cómo podemos crear uno en GitHub (servicio host para repositorios Git): 1. Primero nos situaremos en https://github.com/ y crearemos una cuenta para poder usarlo. 2. Seguidamente creamos un repositorio con el mismo nombre que nuestro proyecto y nos apuntaremos el URL que nos devuelva la operación. 3. A continuación, añadiremos el repositorio remoto, que llamaremos “origin” en nuestro proyecto de la siguiente forma. Hay que introducir el URL que habíamos obtenido en el punto anterior. C:\Ej100_angular\084_testGit>git remote add origin https://.../084_testGit.git Y por último enviaremos nuestro repositorio local al repositorio remoto con el siguiente comando: C:\Ej100_angular\084_testGit>git push –u origin master Desde GitHub puede comprobar que se ha subido todo el repositorio local. En la vista principal puede ver los cheros con su id. de versión (nombre del 360 El gran libro de Angular commit donde se realizó su último cambio), y también puede observar la opción que nos permitiría ver el histórico de conrmaciones. El gran libro de Angular 361 085 jQuery: Parte I jQuery es un framework JavaScript que simplica la programación de páginas web. La biblioteca que aporta simplica parte de la problemática de trabajar con diferentes navegadores y sus particularidades. La declaración de intenciones de jQuery es “escribir menos para hacer más” (“write less, do more”). La primera versión de jQuery fue desarrollada en 2006 por John Resig y la última versión puede obtenerse desde la web de jQuery ubicada en la siguiente dirección: http://jquery.com//. Importante jQuery resulta de gran ayuda para manipular el DOM y usado en combinación con otras herramientas facilita enormemente la programación en web. A modo de resumen, los temas que trata jQuery son: • • • 362 DOM: estructura que contiene los diferentes objetos existentes en un documento cargado en el navegador (document objet model) o, lo que es igual, modelo de objetos del documento. Selector: expresión mediante la cual podemos seleccionar uno o varios elementos que cumplen con un determinado criterio (ltros: contains, ends with, starts, etc., genéricos: .class, element, #id-). Atributo: de elementos (attr(), prop(), val(), removeAttr(), removeProp(), etc.), de clase (addClass(), removeClass() y hasClass()). El gran libro de Angular • • • Eventos: suceso que se produce en un sistema como consecuencia de una acción interna o externa al mismo y que este es capaz de detectar y controlar (p .ej. click, focus, keydown, etc.). Efectos: básicos (hide(), show() y toggle()), personalizados (animate(), delay(), nish(), stop(), etc.). Formularios: obtener o establecer el valor de un control de un formulario. jQuery es un tema extenso y aquí solo pretendemos presentarlo y realizar algún ejercicio. Invitamos al lector a profundizar un poro más consultando el libro de esta misma colección denominado: Aprender jQuery con 100 ejercicios prácticos. Descargaremos la librería de la siguiente página: http://jquery.com//. Podemos descargar la librería con el texto “ the uncompressed, development jQuery x.y.z”. “z.y.z” será el valor de la versión que dependerá del momento en el que el lector se la descargue. 1. Nos ubicaremos en Ej100_angular y crearemos la carpeta 085_jQuery_I tecleando lo siguiente: C:\Ej100_angular>mkdir 085_jQuery_I En la carpeta, depositaremos la librería descargada de jQuery y la renombraremos como jquery.js. 2. En la carpeta, crearemos una página HTML llamada Hola_Mundo.html con el siguiente contenido: 085 jQuery (I) <script type=”text/javascript” src=”jquery.js”> <script type=”text/javascript”> $(document).ready(function () { $(“body”).css(“color”, “ blue”); }); Hola Mundo La librería no contiene ninguna ruta ya que esta se halla en la misma carpeta que nuestra página. El gran libro de Angular 363 3. La función principal de jQuery ($() o función jQuery) utiliza el método ready() para determinar cuándo se ha cargado completamente el DOM y, entonces, cambiar el color del body a azul seleccionando el body y aplicando css. Guarde la página y obsérvela en el navegador. 4. Ahora en el body, añadiremos un párrafo y dos div (id=“miId” y class=“miClase”) para usarlos con css. 5. Ahora, la función jQuery queda de la siguiente manera: <script type=”text/javascript”> $(document).ready(function () { $(“p”).css(“color”, “blue”); $(“#miId”).css(“color”, “red”); $(“.miClase”).css(“color”, “green”); }); Y el body contendrá: 364 El gran libro de Angular Hola Mundo Esto es un parrafo Esto es un bloque div con identicador Esto es un bloque div con clase Guardemos la página y veamos cómo queda en el navegador. 6. Por último, añadimos dos botones para poner/quitar un fondo y un marco usando la clase toggleClass. 7. Para ello, modicamos la función jQuery para que contenga lo siguiente: $(document).ready(function () { $(“p”).css(“color”, “blue”); $(“#miId”).css(“color”, “red”); $(“.miClase”).css(“color”, “green”); $(“#bt_fondo”).click(function () { $(“#bloque”).toggleClass(“fondo”); }); $(“#bt_marco”).click(function () { $(“#bloque”).toggleClass(“marco”); }); }); Detrás de la etiqueta y antes del cierre de añadiremos este bloque para el estilo: El gran libro de Angular 365 <style> .fondo { background: #58FAF4; } .marco { color: blue; border-style: solid; border-width: 3px; } Y el body, para que quede así: Hola Mundo Esto es un parrafo Esto es un bloque div con identicador Esto es un bloque div con clase Guardamos la página y la recargamos en el navegador. Probamos pulsando el botón Fondo, pulsando el botón Marco y pulsando ambos botones. 366 El gran libro de Angular 086 jQuery: Parte II En el siguiente ejercicio, vamos a realizar una prueba con los métodos básicos hide(), show(), toggle(), fadeIn() y fadeOut() y, posteriormente, añadiremos alguna animación con los efectos animate(), delay() y slideToggle(). 1. Nos ubicamos en Ej100_angular y creamos la carpeta 085_jQuery_II tecleando lo siguiente: C:\Ej100_angular>mkdir 085_jQuery_II En la carpeta, depositaremos la librería descargada de jQuery del ejercicio anterior. 2. En la carpeta, crearemos una página HTML llamada 086_jQuery_II.html con el siguiente contenido: El gran libro de Angular 367 085 jQuery (II) <script type = “text/javascript” src = “jquery.js”> <script type = “text/javascript”> $(document).ready(function(){ $(“#b_hide”).click(function(){ $(“#d1”).hide(); resaltar(“hide”); }); $(“#b_show”).click(function(){ $(“#d1”).show(); resaltar(“show”); }); $(“#b_toggle”).click(function(){$(“#d1”).toggle();resaltar(“toggle”);}); $(“#b_reset”).click(function(){location.reload();}); function resaltar(texto){ $(“#res”).html(texto).fadeOut(1000,’linear’,function(){ $(this).html(“”).fadeIn(); }); } }); <style> div {width: 240px;height:90px;background-color:#00BFFF; margin:1px; padding:1px; border-style:groove;border-width:5px; font-size:18px;} div#d1 {width: 220px;height:70px;background-color:#40FF00; margin:4px; padding:1px; border-style:groove;border-width:5px; font-size:18px;} div#msg {width: 240px;height:30px;background-color:#80FF00; margin:1px; padding:1px; border-style:solid; border-width:5px; font-size:25px;border-color:#0000FF;text-align:center;} .cb {width: 80px; height:30px;} .cbr {width: 254px; height:30px;} <span id=”res”/> 368 El gran libro de Angular Guarde el archivo y ábralo en el navegador. Pulse sobre el botón hide() y observe que en la parte inferior aparece el texto hide brevemente y luego se desvanece al mismo tiempo que el bloque superior en verde se oculta. 3. Pulse sobre el botón show() y observe que, además de mostrar el texto en la parte inferior, el bloque verde vuelve a aparecer. Importante jQuery dispone, entre otras muchas funcionalidades, de una gran cantidad de efectos que dan vistosidad a nuestras páginas y aplicaciones web. 4. Pulse sobre el botón toggle() y vea como el bloque aparece y desaparece alternativamente, de forma que si se está mostrando se oculta y si está oculto se visualiza. El gran libro de Angular 369 5. El botón reset vuelve a recargar la página y la deja en su estado inicial. 6. A continuación, vamos a añadir una animación y, para ello, añadiremos dos botones más en una la nueva detrás de los ya existentes con el siguiente código: … También añadimos el siguiente código justo después de $(document).ready(function(){: var vel1 = 4000; var vel2 = 100; var vd1 = false; $(“#b_animate”).click(function () { resaltar(“animate”); vd1 = !vd1; $(“#d1”).animate({height: “toggle”,width: “toggle”}, vel1); $(“#d2”).animate({height: “toggle”,width: “toggle”}, vel1); }); $(“#b_delay”).click(function () { resaltar(“delay-slideToggle”); if (!vd1) { $(“#d1”).delay(vel2).slideToggle(function (){ $(“#d2”).delay(vel2).slideToggle(); }); } else { $(“#d2”).delay(vel2).slideToggle(function () { $(“#d1”).delay(vel2).slideToggle();}); } }); 370 El gran libro de Angular Guarde la página y compruebe su funcionamiento en el navegador. Pulse sobre el botón animate() para ver que el bloque superior se va haciendo pequeño progresivamente hasta desaparecer y, a continuación, vuelva a pulsarlo para ver como aparece de nuevo lentamente. Por último, pulse sobre delay() para ver que desaparece verticalmente con un cierto retardo. El gran libro de Angular 371 087 Bootstrap: Introducción Bootstrap es un framework que facilita el desarrollo web facilitando la adaptación de las pantallas de nuestra aplicación a los diferentes tamaños de dispositivos. Combina HTML, CSS y JavaScript y su curva de aprendizaje es muy asequible. Existe mucha información en Internet, aunque sugerimos visitar el siguiente link https:// v4-alpha.getbootstrap.com/, ya que nos permite realizar diversas acciones como, por ejemplo, descargar la librería para trabajar en local, consultar la documentación del framework, ver muchos ejemplos que podemos copiar y adaptar a nuestros desarrollos, etc. Al acceder a esta página, hallamos un menú desde el que podemos acceder a diversas opciones entre las que destacamos Documentation. Si accedemos a Documentation, veremos una introducción explicando qué es Bootstrap y unas indicaciones sobre cómo podemos empezar a utilizarlo rápidamente, entre otras opciones. Al margen de esto, en la parte de la derecha disponemos de una caja de texto ‘Search’, que nos permitirá localizar fácilmente el recurso que buscamos según vamos tecleando su nombre. Bajo dicha caja de texto, disponemos de una serie de links organizados en forma de columnas que nos permitirá acceder a los temas de una forma organizada en función de lo que necesitemos. Sin lugar a dudas, todas las opciones que nos ofrece el menú de la página de Bootstrap son interesantes, pero nosotros vamos a destacar las siguientes: 372 El gran libro de Angular Opción Comentario Layout Permite denir estilos globales y estructurar nuestras páginas. (Overview, Grid, Media object y Responsive utilities) Contents Uso de contenedores y diseño basado en anchos mínimos para que nuestra aplicación se ajuste según cambie el tamaño de la vista. (Reboot, Typography, Code, Images, Tables y Figures) Components Ofrece un conjunto de componentes que podemos copiar y pegar en nuestro código para que, con unos pequeños ajustes, puedan utilizarse fácilmente. (Alerts, Badge, Breadcrumb, Buttons, Button group, Card, Carousel, Collapse, Dropdowns, Forms, Input group, Jumbotron, List group, Modal, Navs, Navbar, Pagination, Popovers, Progress, Scrollspy y Tooltips) Utilities Conjunto de clases que pretenden facilitar tareas frecuentes como el uso de colores, alineaciones, posicionamiento, espaciados, bordes, etc. (Borders, Clearx, Close icon, Colors, Flexbox, Display property, Image replacement, Invisible content, Position, Responsive helpers, Screenreaders, Sizing, Spacing, Typography y Vertical align) A continuación, vamos a crear una pequeña aplicación sobre la que copiaremos el template que nos encontramos al acceder a Documentation, concretamente en el apartado Starter template. Si pulsamos sobre Copy, copiaremos todo el texto que se propone como template. El gran libro de Angular 373 A continuación, vamos a crear una aplicación en la que mostraremos cómo empezar a usar Bootstrap rápidamente y de forma sencilla. 1. En primer lugar, nos ubicaremos en Ej100_ angular y teclearemos ng new btIntro para crear nuestro nuevo proyecto. 2. Seguidamente, renombraremos el proyecto escribiendo lo siguiente: Importante Utilice Bootstrap para facilitar muchas de las tareas rutinarias que un desarrollo puede comportar y para aprovechar las mejoras que se incorporan periódicamente a este framework. C:\Ej100_angular>rename btIntro 087_btIntro A continuación, nos ubicaremos en 087_btIntro y arrancaremos la aplicación para comprobar cómo funciona en nuestro navegador. Para ello, teclearemos lo siguiente: C:\Ej100_angular>cd 087_btIntro C:\Ej100_angular\087_btIntro>ng serve Ahora, abrimos nuestro proyecto y editamos el archivo src/app/app.component.html. En el mismo pegaremos el contenido de la plantilla que nos ofrece el apartado Starter template comentado antes. 3. Insertaremos un div para encerrar nuestro “ Hello, world!” y que quede de la siguiente manera: Hello, world! La clase container-uid permite que el contenedor ocupe todo el ancho del visor. Guardamos el archivo y acudimos al navegador a ver el aspecto de la página. 374 El gran libro de Angular 4. Seguidamente, vamos a Utilities->Color de la página de Bootstrap y copiamos la siguiente sentencia para pegarla a continuación de “ Hello, world!”: Duis mollis, est non commodo luctus, nisi erat porttitor ligula. Modicamos el texto “Duis …lígula” para que ponga un texto más personalizado como por ejemplo “Mi texto de pruebas”, guardamos el archivo y vemos el resultado en el navegador. La clase text-success es la encargada de la apariencia del texto. 5. A continuación, creamos la carpeta images bajo src (src/images) y copiamos una imagen cualquiera que podemos llamar img1.jpg. El gran libro de Angular 375 6. Vamos a la página de Bootstrap y en Utilities->Borders localizamos Border-radius para copiar lo siguiente y pegarlo a continuación del párrafo insertado anteriormente: Luego, adaptamos lo copiado para que quede de la siguiente manera: La clase rounded-circle produce un redondeo sobre la imagen, img-uid crea una escala de imagen acorde a cada dispositivo y w-50 indica que la imagen ha de ocupar el 50% del tamaño de la ventana. Pruebe de cambiar el tamaño de la ventana y observe que la imagen se redimensiona para ocupar el 50% del ancho de la misma. 376 El gran libro de Angular 088 Bootstrap: Layout. El sistema Grid En el apartado Layout de la documentación Bootstrap, encontrará todo lo relacionado con las herramientas de de diseño que nos ofrece el framework. Entre estas, cabe destacar el Sistema “Grid” de Bootstrap. El sistema de “Grid” de Bootstrap nos permitirá diseñar y alinear contenidos, mediante contenedores, las y columnas. Vamos a ver todo su potencial a través de varios ejercicios. Importante Mediante el sistema Grid de 12 Columnas de Bootstrap podremos estructurar el contenido Web de nuestras aplicaciones. Una de sus principales ventajas es la facilidad con la que nos permite la creación de distintos diseños para distintos tipos de pantalla (móvil, ordenador, etc.). 1. Nos ubicaremos en ej100_angular y crearemos el proyecto tecleando ng new btLayout. Luego, lo renombraremos para que haga referencia a nuestro número de ejercicio ejecutando rename btLayout 088_ btLayout y, nalmente, pondremos en marcha la aplicación ejecutando ng serve desde dentro la carpeta 088_btLayout. A continuación abriremos el proyecto con Atom. 2. Seguidamente añadiremos los links de Bootstrap (https://v4-alpha. getbootstrap.com) en index.html para poder hacer uso de sus hojas de estilo. Consulte “087 Bootstrap …” para más información. 3. Ahora editaremos src/app/app.component.html y añadiremos el siguiente código: 088 Bootstrap Layout Contenido... Con las clases de Bootstrap .container-uid y .container estamos deniendo un contenedor de tamaño variable y otro de tamaño jo. Observe el resultado en el navegador. Si modica el tamaño del navegador podrá obEl gran libro de Angular 377 servar cómo el primer contenedor se adapta a ello mientras que el segundo mantiene el tamaño jo. 4. Dentro los contenedores, deniremos nuestras las y columnas mediante las clases .row y .col-sm. El sistema “Grid” de Bootstrap nos permite denir un máximo de 12 columnas de tamaño 1. A partir de aquí, podemos realizar las combinaciones que queramos: una la con una columna de tamaño 2, otra de tamaño 4 y otra de tamaño 6, una la con una columna de tamaño 9 y otra de tamaño 3, etc. Vamos a crear una par de las con distintas conguraciones de columnas. Para ello, sustituye el segundo contenedor que habíamos creado en src/ app/app.component.html, por el siguiente: col-sm-2 col-sm-4 col-sm-6 col-sm-9 col-sm-3 5. Para facilitar la comprensión de este ejercicio, crearemos un borde para cada una de las “celdas” creadas a partir de la denición de las y columnas. Para ello, vamos a añadir la siguiente clase en nuestra hoja de estilo src/app/ app.component.css: .celda { border: #cdcdcd medium solid; } Finalmente aplicaremos la clase a cada una de las columnas que hemos implementado antes en src/app/app.component.html: 378 El gran libro de Angular col-sm-2 … 6. Observe en el navegador el resultado de este código. 7. Con Bootrsap tenemos 4 tipos de columnas. Cada una de ellas se utiliza para mostrar en distintos dispositivos con pantallas de resolución distinta: col-xs (para pantallas de resolución menor a 768px), col-sm (para pantallas de resolución mayor o igual a 768px), colmd (para pantallas de resolución mayor o igual a 992px) y col-lg (para pantallas de resolución mayor o igual a 1200px). Estos tipos de columna se pueden usar a la vez, cosa que nos permitirá hacer diseños para todo tipo de pantallas al mismo tiempo. Veamos un ejemplo. Añada la siguiente nueva la en src/app/app.component.html: .. col-sm-3 col-md-6 col-sm-9 col-md-6 8. Observe en el navegador el resultado. Fíjese cómo, en la nueva la, se aplica una u otra conguración según el tamaño del navegador. 9. De forma parecida, también tenemos otros tipos de clases que se aplican según el tamaño de pantalla. Estas son las de ocultar o mostrar columnas: .hidden-xs, .hidden-sm, etc., visible-xs, .visible-xm, etc. El gran libro de Angular 379 10. Usando la clase .offset-xxtamaño, podremos desplazar columnas. Cuando desplazamos una columna, lo que hacemos realmente es crear una columna vacía a la izquierda de la columna desplazada. Veamos un ejemplo. Añada la siguiente nueva la en src/app/app.component.html y observe el resultado en el navegador: col-sm-2 offset-sm-4 col-sm-2 offset-sm-4 11. Para terminar, vamos a ver cómo podemos anidar columnas. Para ello, simplemente crearemos nuevas las (rows) dentro de columnas. Añada la siguiente nueva la en src/app/app. component.html y observe el resultado en el navegador: col-sm-3 col-sm-4 col-sm-4 col-sm-4 380 El gran libro de Angular 089 Bootstrap: Tables Dentro del apartado Content, podemos encontrar un tema dedicado a las tablas el cual nos permitirá añadir un aspecto y funcionalidad a las mismas simplemente añadiendo alguna de las clases que se ofrecen. Algunas clases afectan a la tabla, otras a los encabezados, otras a las las, etc. A continuación, fabricaremos una aplicación para probar algunos ejemplos y ver su resultado en el navegador. Importante Cree tablas aprovechando la plantilla que ofrece Bootstrap y preocúpese solo por rellenar su contenido. 1. En primer lugar, nos ubicaremos en Ej100_angular y crearemos el proyecto btTables tecleando ng new btTables. 2. Seguidamente, renombraremos el proyecto para que haga referencia a nuestro número de ejercicio. Para ello, estando ubicados en el directorio Ej100_angular, escribiremos lo siguiente: C:\Ej100_angular>rename btTables 089_btTables Ahora, abrimos nuestro proyecto con nuestro editor (en nuestro caso usamos Atom) y abrimos el archivo app.component.ts para modicar el título (title) y poner, por ejemplo, “089 Bootstrap Tables”. 3. Después accedemos a la página de Bootstrap y copiamos el contenido que se halla en Documentation->Quick start, que empieza por: rel=”stylesheet” href=”https://maxcdn.bootstrapcdn. com/bootstrap/4.0.0- ... El gran libro de Angular 381 Dicho contenido lo pegamos en la primera línea del archivo app.component.html dejando que el resto del archivo contenga lo siguiente: {{title}} Luego, en la misma página de Bootstrap, veremos que tras la sentencia anterior, se hallan 3 líneas que hacen referencia a jquery, tether y bootstrap, que empiezan por: <script src=”https://code.jquery.com/jquery... Pulsamos el botón Copy y las pegamos al nal de nuestro archivo app.component. html. 4. A continuación, nos ubicaremos en 089_ btTables y arrancaremos la aplicación con ng serve para comprobar cómo funciona en nuestro navegador. Para ello, teclearemos lo siguiente: C:\Ej100_angular>cd 089_btTables C:\Ej100_angular\088_btTables>ng serve A partir de aquí, en la página de Bootstrap, situados en Documentation, teclearemos en la caja de texto Search, la palabra tables y seleccionaremos de la lista resultante precisamente Tables. 382 El gran libro de Angular 5. Además de revisar el contenido de esta página, podemos copiar el primer ejemplo pulsando sobre el botón Copy que hay debajo del primer ejemplo, y pegarlo en app.component.html, justo debajo de nuestro 1v693h

    que cierra el título (title). Lo primero que destacamos es que al tag table, le asignamos la clase “table”. 6. Si consultamos el navegador donde está corriendo la aplicación, veremos el resultado de esta acción. 7. A continuación, veremos el siguiente ejemplo propuesto por Bootstrap que simplemente muestra en vídeo inverso el contenido de la tabla añadiendo la clase tableinverse a la clase ya existente y dejando el tag de table con el siguiente contenido:









    8. Observe el resultado en el navegador. El gran libro de Angular 383 9. Sustituyamos a continuación la clase table-inverse por table-bordered para que quede de la siguiente manera:




    Observe el resultado en el navegador. 10. Añada la clase table-hover para que la la cambie de color al pasar el puntero del ratón sobre la misma y deje el siguiente contenido:










































    {{title}}







    <strong>Well done! You successfully read this important alert message.








    Well done!

    Aww yeah, you successfully read this important alert message. This example text is going to run a bit longer so that you can see how spacing within an alert works with this kind of content.

    Whenever you need to, be sure to use margin utilities to keep things nice and tidy.



    <strong>Holy guacamole! You should check in on some of those elds below.






    ...













    <strong>Hola! Prueba de link
    target=”_blank”

    class=”alert-link” rel="nofollow">a

    Google.














    , Checkbox, etc.

    Buttons Los estilos aportados para los botones nos permiten personalizar el aspecto de diferentes elementos en nuestros formularios y diálogos. Además de cambiar la forma de visualizar los botones en si mismos, podemos cambiar el aspecto de elementos como, por ejemplo, los de tipo





























    {{title}}





    {{title}}


































    Guarde el archivo pruebe su funcionamiento en el navegador pulsando sobre los botones.

    El gran libro de Angular

    399

    10. Para acabar, probaremos cómo cambiar el tamaño de los botones. Añadiremos la clase btn-group-sm al primer grupo de botones que hemos copiado para que la clase del div quede con lo siguiente:

    Los botones se verán pequeños (sm->small). Guarde archivo y compruébelo en el navegador.

    11. Ahora, mostremos en tamaño grande (lg->large) los botones que mostramos verticalmente y, para ello, añadiremos la clase btn-group-lg junto a la clase btn-group-vertical quedando así:

    Guarde el archivo y compruebe cómo se visualiza en el navegador.

    400

    El gran libro de Angular

    092

    Bootstrap: Cards

    Las Cards son un tipo de contenedor que ofrece multitud de opciones para encabezados, pies de página, colores de fondo, etc. Una de las ventajas es que son exibles y extensibles. Además, se construyen con muy poca cantidad de código y están fabricadas con exbox (sistema de elementos exibles que facilita el posicionamiento de dichos elementos cuando cambia el tamaño de la página). En esta página nos encontramos diversos temas que resumimos a continuación: • • •



    • • • •

    • • •

    Content types: permite incluir una gran variedad de elementos en su interior. Blocks: facilita una sección bien espaciada Importante dentro de una tarjeta. Titles, text y links: dentro de una tarjeta Use Cards para podemos encontrarnos con diferentes partes organizar mejor su (títulos, subtítulos, textos, links, etc.) que poseen información. Es ideal su correspondiente clase (card-title, cardpara tratar chas donde subtitle, card-text, card-link, etc.) para un determinado objeto facilitar su tratamiento. de base de datos puede mostrar diferentes Images/overlays: podemos añadir una imagen atributos con diferentes en la parte superior o inferior de la tarjeta. aspectos y ubicaciones. Podemos usar una imagen como fondo y poner el texto encima. List groups: crea lista de contenido en una tarjeta. Kitchen sink: permite combinar diferentes tipos de contenido sobre un ancho jo. Header and footer: permite añadir encabezados y pies. Sizing: podemos usar tags de grid para disponer las tarjetas en las o columnas según necesitemos. Recordemos que podemos distribuir nuestros elementos en 12 columnas que podemos agrupar como nos interese mediante expresiones col-X, siendo X el número de columnas que pretendemos ocupar con el elemento. Using utilities: podemos denir que usen ancho variables como, por ejemplo, w-50 (ocupa el 50% del ancho de la página). Text alignment: es posible alinear el texto fácilmente (izquierda, centro, derecha). Navigation: añade navegación al encabezado de la tarjeta. El gran libro de Angular

    401

    Card styles: diferentes tipos de fondos, bordes y colores (Background variants, Outline cards). • Card layout: permite visualizar las tarjetas en series (Card groups, Card decks, o unidas entre sí, Card columns). A continuación, vamos a realizar un ejercicio en el que veremos algunos ejemplos de los descritos en la página. •

    1. En primer lugar, nos ubicamos en Ej100_angular y creamos el proyecto btCards tecleando ng new btCards. 2. Seguidamente, renombraremos el proyecto para que haga referencia a nuestro número de ejercicio. Para ello, ubicados en el directorio Ej100_ angular, escribiremos lo siguiente: C:\Ej100_angular>rename btCards 092_btCards

    Abrimos nuestro proyecto (por ejemplo, con Atom) y abrimos el archivo app.component.ts para modicar el título (title) y poner por ejemplo “092 Bootstrap Cards”. 3. Igual que en ejercicios anteriores, modicaremos el archivo app.component. html para insertar al principio y al nal del mismo las referencias a la hoja de estilos de Bootstrap (al principio) y a jquery, tether y bootstrap (al nal):
    Añadiremos un elemento div con la clase container alrededor de nuestro title para que quede así:

    {{title}}



    En la página de Bootstrap dedicada a Cards (https://v4-alpha.getbootstrap. com/components/card/) localizamos el apartado Titles, text, and links y copiamos (Copy) el ejemplo que muestra:

    402

    El gran libro de Angular

    Card title

    Card subtitle

    Some quick example text to build on the card title and make up the bulk of the card’s content.

    Another link


    Lo pegamos detrás del tag que cierra el título, guardamos el archivo y arrancamos la aplicación (con ng serve desde C:\Ej100_angular>092_ btCards) para ver cómo se ve nuestra aplicación en el navegador.

    4. Modiquemos el tamaño de nuestra pantalla y comprobemos cómo la tarjeta se adapta a cada tamaño.

    El gran libro de Angular

    403

    5. Para el siguiente ejemplo, necesitaremos disponer de una imagen, la cual, al igual que explicamos en el ejercicio 087, almacenaremos en una carpeta creada en nuestro proyecto y denominada src/images. La imagen la llamaremos img1.jpg.

    6. El siguiente ejemplo es de los más completos ya que mezcla diferentes funcionalidades en uno solo. Dicho ejemplo lo fabricaremos localizando el apartado Kitchen sink y copiando (Copy) su contenido para pegarlo a continuación del cierre del tag div de la tarjeta anterior: …
    ”Card

    Card title

    Some quick example text to build on the card title and make up the bulk of the card’s content.



    404

    El gran libro de Angular

    • Cras justo odio
    • Dapibus ac facilisis in
    • Vestibulum at eros


    Añadimos un
    entre ambas tarjetas y modicamos el src del código copiado para que quede de la siguiente manera: ”Card

    Guardamos y vemos el archivo en el navegador.

    7. Por último, localice el ejemplo asociado al apartado Image overlays, copie su contenido (Copy) y péguelo a continuación del div correspondiente al ejemplo anterior. Inserte un
    entre div para dejar una la de separación. El gran libro de Angular

    405

    8. Modique el src para que apunte a images/img1.jpg. 9. Guarde el archivo y visualícelo en el navegador.

    10. Cambie el navegador de tamaño (el ancho) y compruebe la adaptación de esta tarjeta.

    11. Le invitamos a que pruebe más ejemplos para comprobar las diversas funcionalidades expuestas en la página de Cards de Bootstrap.

    406

    El gran libro de Angular

    093

    Bootstrap: Instalación local

    Otra forma de trabajar con las librerías de Bootstrap es descargándolas sobre nuestro propio puesto de trabajo y referenciándolas desde nuestro proyecto. Esto aporta alguna ventaja como puede ser poder trabajar sin conexión y un aumento de la eciencia. Así pues, en los próximos ejercicios, usaremos la instalación local para probar una nueva forma de utilizar Bootstrap. Para conseguir esta instalación, descargaremos las librerías de Bootstrap, jQuery y Tether y las incluiremos en nuestro proyecto. Veamos los detalles de cada una de las descargas:

    Importante Instale localmente las librerías para poder trabajar con conexión a Internet y para agilizar la carga de las páginas como alternativa al uso de referencias CDN.



    Descarga de bootstrap: en la página https://v4-alpha.getbootstrap.com/ getting-started// descargaremos Bootstrap CSS and JS pulsando sobre el botón “ Bootstrap”. Dependiendo del momento en el que nos descarguemos el archivo, su nombre (o versión) puede variar, pero, en denitiva, nos ofrecerá descargar un archivo similar al siguiente: bootstrap4.0.0-alpha.6-dist.zip. Podemos descargarlo en un directorio temporal para poder extraerlo más fácilmente. Una vez descargado, lo extraemos y comprobamos que en su interior hay dos carpetas (css y js), cada una de ellas con distintas librerías.



    Descarga de jQuery: acudiremos a la siguiente página: https://jquery. com// y localizaremos la opción: the compressed, production jQuery 3.2.1 slim build (https://code.jquery.com/jqueryEl gran libro de Angular

    407

    3.2.1.slim.min.js). Esta es la versión comprimida que ocupa menos espacio y que será suciente para conseguir nuestro propósito.



    Descarga de Tether: acudiremos a la página: http://tether.io/ y pulsaremos sobre el botón: ZIP (v1.3.3) para descargar un chero con un nombre similar al siguiente: tether-1.3.3.zip. En nuestro temporal, lo descomprimimos y más tarde extraeremos lo necesario.

    Una vez que ya disponemos de todas las librerías que vamos a necesitar, crearemos un proyecto para adjuntarlas y usarlas. 1. En primer lugar, nos ubicamos en Ej100_angular y creamos el proyecto btInsLocal tecleando ng new btInsLocal. 2. Seguidamente, renombraremos el proyecto para que haga referencia a nuestro número de ejercicio. Para ello, estando ubicados en el directorio Ej100_angular, escribiremos lo siguiente: C:\Ej100_angular>rename btInsLocal 093_btInsLocal

    408

    El gran libro de Angular

    Abrimos nuestro proyecto (por ejemplo, con Atom) y, bajo la carpeta src/ assets, crearemos las carpetas sobre las que copiaremos, respectivamente, las librerías indicadas a continuación (1): Carpeta

    Librería

    bootstrap4/css

    bootstrap.min.css

    bootstrap4/js

    bootstrap.min.js

    jquery

    jquery.slim.min.js

    tether

    tether.min.js

    A continuación, hemos de modicar el archivo angular-cli.json para hacer referencia a estas librerías. Para ello, una vez abierto este archivo, localizamos el apartado que contiene lo siguiente: “styles”: [ “styles.css” ], “scripts”: [],

    Y lo modicamos por este contenido: “styles”: [ “styles.css”, “assets/bootstrap4/css/bootstrap.min.css” ], “scripts”: [ “assets/jquery/jquery-3.2.1.slim.min.js”, “assets/tether/tether.min.js”, “assets/bootstrap4/js/bootstrap.min.js” ],

    Guardamos el archivo y abrimos el archivo app-component.ts para modicar el contenido de title y poner “093 Bootstrap instalación local”. 3. Desde el directorio C:\Ej100_angular>093_btInsLocal arrancaremos la aplicación tecleando ng serve y comprobaremos en el navegador cómo se visualiza la misma sin ningún error. El gran libro de Angular

    409

    4. Para comprobar que la instalación funciona correctamente, podemos acudir a la página de Bootstrap Documentation y, en Search, buscar Colors para acceder a la página https://v4-alpha.getbootstrap.com/utilities/colors/. Una vez aquí, localizamos el ejemplo que hay antes del apartado Dealing with specicity y copiamos las tres primeras líneas del mismo. Una vez copiadas, las pegaremos al nal del contenido de nuestro archivo app. component.html justo debajo del cierre de de nuestro título. 5. Para que se visualice mejor, envolveremos todo el contenido de la página en un div con la clase container, de forma que todo quede de la siguiente manera:

    {{title}}

    Nullam id dolor id nibh ultricies vehicula ut id elit.
    Duis mollis, est non commodo luctus, nisi erat porttitor ligula.
    Maecenas sed diam eget risus varius blandit sit amet non magna.


    Guardamos el archivo y vemos cómo se visualiza en el navegador.

    6. Hagamos alguna prueba más buscando el tema Typography (por favor, use Search) y, dentro de la página, localice Text transform para copiar el ejemplo propuesto y pegar a continuación de lo anterior (antes del cierre del último






    Lowercased text.

    Uppercased text.

    CapiTaliZed text.





    Bold text.

    Normal weight text.

    Italic text.



































    {{title}}









    {{title}}







    ”First













    ”First



    Seguidamente, añadiremos subtítulos a cada imagen y, localizando el apartado With captions, copiaremos el bloque que hay justo debajo de la imagen que contiene la clase carousel-caption: ”...”

    ...

    ...



    Pegaremos dicho bloque bajo el tag de cada una de nuestras imágenes y añadiremos un texto para los tags

    y

    . Por ejemplo, el bloque asociado a la imagen 1 quedaría así:

    418

    El gran libro de Angular

    ”First

    Imagen 1

    Esta es una prueba de la imagen 1



    Copiemos dicho bloque sobre el resto de imágenes modicando Imagen 1 por la que corresponda, guardemos el archivo y visualicemos cómo queda en el navegador. Compruebe cómo pulsando sobre los indicadores existentes a pie de página, se muestra la imagen asociada a cada uno de los mismos.

    El gran libro de Angular

    419

    095

    Bootstrap: Collapse

    Mediante el complemento Collapse, podemos mostrar u ocultar determinadas partes de nuestra página facilitando la optimización del espacio y proporcionando un efecto visual muy agradable. La idea es que podamos colapsar o expandir un bloque como si fuera un acordeón. En el siguiente ejercicio, vamos a poner en marcha uno de los ejemplos expuestos en la página de Bootstrap dedicado a este tema (https://v4-alpha.getbootstrap.com/components/collapse/) y lo personalizaremos un poco para poder jugar con él. 1. En primer lugar, nos ubicamos en Ej100_angular y creamos el proyecto btCollapse tecleando ng new btCollapse. 2. Seguidamente, renombraremos el proyecto para que haga referencia a nuestro número de ejercicio. Para ello, ubicados en el directorio Ej100_angular, escribiremos lo siguiente: C:\Ej100_angular>rename btCollapse 095_btCollapse

    Abrimos nuestro proyecto (por ejemplo, con Atom) y abrimos el archivo app.component.ts para modicar el título (title) y poner por ejemplo “095 Bootstrap Collapse”. 3. Tal y como explicamos en el ejercicio anterior, instalaremos las librerías de forma local descargándolas e incorporándolas en el proyecto bajo la carpeta assets y también modicaremos el archivo angular-cli.json para hacer referencia a estas librerías. Por favor, revise el ejercicio 093 si tiene alguna duda. 4. A continuación, en nuestro archivo app.component.html añadiremos un elemento div con la clase container alrededor de nuestro title para que quede así:

    {{title}}



    420

    El gran libro de Angular

    En la página de Bootstrap/Collapse localizamos el primer ejemplo y copiamos su contenido para pegarlo a continuación del cierre del tag que cierra nuestro title: …

    Link with href

    Anim pariatur cliche reprehenderit, enim eiusmod high life accusamus terry richardson ad squid. Nihil anim kefyeh helvetica, craft beer labore wes anderson cred nesciunt sapiente ea proident.


    Guardaremos el archivo y arrancaremos la aplicación ubicándonos en C:\ Ej100_angular\095_btCollapse y tecleando ng serve. Observe el resultado en el navegador accediendo al URL http:// localhost:4200/. Importante Organice su contenido en poco espacio aplicando Collapse y haciendo que la información se muestre cuando sea requerida.

    El gran libro de Angular

    421

    5. Pulsemos ambos botones para comprobar cómo se muestra y oculta el bloque asociado.

    6. Ahora, modicaremos un poco el código copiado para personalizarlo y simplicarlo. Básicamente, lo que haremos es rebautizar el id del div asociado a la clase collapse y las referencias al mismo, tanto en el tag como

    Mi bloque uno


    Guardamos el archivo y comprobamos de nuevo cómo queda en el navegador. Observe que el bloque se muestra y oculta alternativamente sea cual sea el botón que pulsemos.

    422

    El gran libro de Angular

    7. Para dar un poco más de juego al ejemplo, introduciremos un bloque dentro de otro para anidar los acordeones. 8. En este caso, copiaremos debajo del texto “Mi bloque uno”, un bloque similar al copiado y adaptado inicialmente, el cual empieza en el tag

    y acaba en el tag

    apunte a un bloque denominado “dos”, y el botón tipo “button” apunte a un div llamado “tres”. En denitiva, el bloque que contenía el texto “Mi bloque uno” quedará de la siguiente manera:
    Mi bloque uno

    Dos Con Ref

    Mi bloque dos
    Mi bloque tres




































    {{title}}



    {{title}}



    Guardamos el archivo y arrancaremos la aplicación desde C:\Ej100_angular\096_btDropDown tecleando ng serve. Observe el resultado en el navegador en el URL http://localhost:4200/.

    5. Pulse sobre la lista para desplegarla y compruebe que funciona perfectamente.

    426

    El gran libro de Angular

    6. A continuación, crearemos un bloque de tipo “row” y dentro del mismo, dos bloques de tipo “col” donde reubicaremos nuestro elemento recién copiado y un nuevo div para mostrar el resultado de la selección, respectivamente, la cual, implementaremos a continuación. Las columnas ocuparán cinco columnas de la rejilla de Bootstrap (12 columnas), y así dejamos margins y paddings (m-1 y p-1) entre bloques. 7. Ahora, el código de nuestro app.component.html quedará de la siguiente manera:

    {{title}}

    Opcion: {{ res1 }}


    En el chero styles.css incluiremos la denición de la clase borde con el siguiente contenido:

    El gran libro de Angular

    427

    .borde{ border: 3px solid blue; }

    En el archivo app.component.ts, la clase AppComponent quedará con el siguiente contenido: export class AppComponent { title = ‘096 Bootstrap Dropdowns’; res1:string = “Azul”; color1:string = ‘#A9F5F2’; onClick(par:string){ this.res1=par; switch(this.res1) { case “Verde”: this.color1 = “#A9F5BC”; break; case “Amarillo”: this.color1 = “#FFFF00”; break; default: this.color1 = “#A9F5F2”; break; } } }

    Guardemos el archivo y veamos cómo queda en el navegador.

    8. Añadimos la clase w-100 al botón que dene el dropdown con id=“menu1” para que quede así:
    Guardamos el archivo y vemos que el botón del Dropdown ocupará todo el bloque.

    428

    El gran libro de Angular

    9. Probemos desplegar el botón y seleccionar Verde o Amarillo.

    10. Sustituyamos la clase btn-secondary del primer botón para poner btnsuccess para ver cómo queda.

    11. Por último, añadiremos la clase btn-sm al primer botón para ver cómo el botón se muestra más pequeño. El código asociado al botón queda de la siguiente manera:



    El gran libro de Angular

    429

    097

    Bootstrap: Forms

    Bootstrap ofrece una gran cantidad de controles y clases para la fabricación de formularios con elementos de diferentes estilos y tamaños. Puede consultar la página en el apartado Forms de Bootstrap (https://v4-alpha.getbootstrap.com/components/forms/). Por defecto, se aplican estilos a todos los controles y estos se apilan verticalmente, ya que Bootstrap establece display: block y width: 100% a casi todos los componentes del formulario. No obstante, podemos usar la clase form-inline para colocar las etiquetas a la izquierda de los campos y hacer que los controles se muestren en la medida de lo posible de forma horizontal. Los clásicos controles soportados son: Input, Textarea, Checkbox, Radio, Select y Controles estáticos. La etiqueta y el input asociados a un campo se suelen agrupar en un div al que se le añade la clase formgroup para optimizar mejor el espacio y obtener una mayor organización. En los controles de tipo input, podemos usar placeholder para mostrar un texto explicativo sobre lo que se solicita. En los controles input, textarea y select, podemos añadir la clase form-control para que el ancho se establezca a width: 100%. Los campos de tipo input pueden ser: de texto (text, ), de fecha (datetime, datetime-local, date, month, time, week), de número (number) y otros (email, url, search, tel, y color).

    Importante Construya sus formularios por bloques y aproveche las funcionalidades que le ofrecen las clases de Bootstrap para ahorrarse tiempo y problemas.

    A continuación, fabricaremos un formulario sencillo con algunos controles para mostrar algunas de las funcionalidades de las clases que Bootstrap ha preparado. 1. Nos ubicamos en Ej100_angular y creamos el proyecto btForms tecleando ng new btForms. 2. Seguidamente, renombraremos el proyecto para que haga referencia a nuestro número de ejercicio. Para ello, estando ubicados en el directorio Ej100_angular, escribiremos lo siguiente:

    430

    El gran libro de Angular

    C:\Ej100_angular>rename btForms 097_btForms

    Abrimos nuestro proyecto (por ejemplo, con Atom) y abrimos el archivo app.component.ts para modicar el título (title) y poner por ejemplo “097 Bootstrap Forms”. 3. Tal y como ya hemos explicado en ejercicios anteriores, instalaremos las librerías de forma local descargándolas e incorporándolas en el proyecto. Por favor, revise el ejercicio 093 si tiene alguna duda. 4. A continuación, en nuestro archivo app.component.html añadiremos un elemento div con la clase container alrededor de nuestro title para que quede así:

    {{title}}



    A continuación del tag anterior, insertaremos un formulario vacío solo con el botón submit: …


    Guarde el archivo y arranque la aplicación ubicándose en C:\Ej100_angular\097_btForms y tecleando ng serve. Observe el resultado en el navegador (http://localhost:4200/).

    5. Ahora, desde de la página de Bootstrap dedicado a Forms, localizamos el tema Form controls y copiamos del primer ejemplo el grupo que hace referencia al exampleInputEmail1:

    El gran libro de Angular

    431

    <small id=”emailHelp” class=”form-text text-muted”>We’ll never share your email with anyone else.


    Lo pegamos antes del botón submit. Guardamos el archivo y vemos cómo queda en el navegador.

    6. Si añadimos la clase form-inline al tag
    veremos cómo los elementos se disponen horizontalmente en la pantalla:



    Eliminamos esta clase para dejarlo como estaba antes y dejar que los controles se apilen verticalmente. 7. Observe como al hacer clic sobre el e-mail, el borde del mismo cambia de color y, al empezar a escribir, desaparece el placeholder.

    432

    El gran libro de Angular

    8. Ahora copiamos el bloque anterior y lo pegamos debajo del mismo para cambiar algunos valores y convertirlo en un input de . Ponemos lo siguiente:
    <small id=”” class=”form-text text-muted”>Introduzca .


    Guardemos el archivo, visualicémoslo en el navegador e introduzcamos algo en el control para comprobar cómo oculta los caracteres introducidos.

    9. En el ejemplo de Bootstrap, buscamos la parte correspondiente al Select1 (sencillo) y la pegamos a continuación del bloque anterior:

    El gran libro de Angular

    433

    <select class=”form-control form-control-sm” id=”exampleSelect1”>


    Guardamos el archivo, y en el navegador desplegamos la lista para ver cómo funciona.

    10. Ahora, en la página de Bootstrap, dentro del apartado Textual inputs, localizaremos el div que contiene el ejemplo example-date-input y pegaremos su contenido a continuación del bloque anterior:

    434

    El gran libro de Angular



    Guardamos la página y en el navegador, desplegaremos el control pulsando sobre la echa.

    11. En el mismo apartado Textual inputs, localizaremos el div que contiene el ejemplo example-time-input y pegaremos su contenido a continuación del bloque anterior:

    El gran libro de Angular

    435



    Guarde el archivo y pruebe en el navegador con el nuevo control para ver su comportamiento.

    436

    El gran libro de Angular

    098

    Bootstrap: List group

    Los List group son elementos que permiten visualizar información mostrándola en forma de lista. En la página se analizan diferentes funcionalidades relativas a las listas como por ejemplo: Active items (para indicar la selección activa), Disabled items (para deshabilitar ítems), Links and buttons (para crear listas a partir de links o de botones), Contextual classes (permite diseñar un fondo y un color con el estado), With badges (permite añadir insignias para mostrar conteos de actividad; p. ej., mensajes no leídos, etc.), Custom content (permite realizar listas personalizadas añadiendo prácticamente cualquier tag ).

    Importante Las listas son un buen recurso para mostrar información o enumerar un grupo de acciones a realizar. Use Bootstrap para fabricar listas apoyándose no solo en elementos de listas clásicos sino también en links y botones.

    En el siguiente ejercicio crearemos un par de listas a las que les añadiremos algunas funcionalidades propuestas en la página de Bootstrap dedicada a List group (https://v4-alpha.getbootstrap.com/components/ list-group/). 1. Nos ubicamos en Ej100_angular y creamos el proyecto btListGroup tecleando ng new btListGroup. 2. Renombraremos el proyecto para que haga referencia a nuestro número de ejercicio tecleando: C:\Ej100_angular>rename btListGroup 098_btListGroup

    Abrimos el proyecto y app.component.ts modicando title con “098 Bootstrap List group”. 3. Instalamos las librerías de forma local descargándolas (revise el capítulo 093). 4. En app.component.html añadiremos un div con la clase container alrededor de title:

    {{title}}



    El gran libro de Angular

    437

    Ahora, copiamos el primer ejemplo de Bootstrap y lo pegamos detrás del tag que cierra title: …
    • Cras justo odio


    Guarde el archivo y arranque la aplicación ubicándose en C:\Ej100_angular\098_btListGroup y tecleando ng serve. Observe el resultado en el navegador (http://localhost:4200/).

    5. Localice el apartado Links and buttons y copie (Copy) el primer ejemplo que empieza así:
    Cras justo odio



    Lo modicaremos para que, al seleccionar un elemento de la lista, se muestre el resultado en un bloque a pie de pantalla y se cambie el color del mismo. Es similar al ejercicio 096_Bootstrap_Dropdowns. 6. Una vez modicado, el bloque quedará con el siguiente contenido:
    Azul

    438

    El gran libro de Angular

    Amarillo
    Opcion: {{ res1 }}


    Seguidamente, modicaremos app.component.ts para que la clase Appcomponent quede así: export class AppComponent { title = ‘098 Bootstrap List group’; res1: string = “?”; color1: string = ‘#D8D8D8’; onClick(par: string) { this.res1 = par; switch (this.res1) { case “Verde”: this.color1 = “#A9F5BC”; break; case “Amarillo”: this.color1 = “#FFFF00”; break; case “Azul”: this.color1 = “#A9F5F2”; break; } } }

    Guarde la aplicación y en el navegador y pulse sobre la lista para ver el resultado.

    El gran libro de Angular

    439

    7. Por último, observaremos el ejemplo descrito en el apartado With badges y añadiremos un span con las clases badge al lado de cada descripción de elemento de lista, quedando de la siguiente manera:
    Opcion: {{ res1 }}


    A la clase Appcomponent del archivo app.component.ts hay que añadirle ciertas variables para contar los clics cada vez que se haga clic sobre un elemento y modicar el método onClick() así:

    440

    El gran libro de Angular

    export class AppComponent { title = ‘098 Bootstrap List group’; res1: string = “?”; color1: string = ‘#D8D8D8’; num1: number = 0; num2: number = 0; num3: number = 0; onClick(par: string) { this.res1 = par; switch (this.res1) { case “Verde”: this.color1 = “#A9F5BC”; this.num2 += 1; break; case “Amarillo”: this.color1 = “#FFFF00”; this.num3 += 1; break; case “Azul”: this.color1 = “#A9F5F2”; this.num1 += 1; break; } } }

    Guarde el archivo y visualícelo en el navegador. Pruebe haciendo clic sobre cualquier elemento y vea cómo se incrementan los contadores.

    El gran libro de Angular

    441

    099

    Bootstrap: Navbar

    Navbar es un elemento contenedor que se muestra en forma de barra y que permite incluir encabezados y opciones que ayudan a la navegación dentro de nuestra aplicación y que ofrece comportamientos responsive. En la página (https://v4-alpha.getbootstrap.com/components/navbar/) que Bootstrap dedica a este tema, podemos encontrar explicaciones sobre: • •

    • • • • • • • • •

    How it Works: contenido uido por defecto, fácil alineamiento, comportamiento responsive, etc. ed content: soporta subcomponentes para mostrar la marca o nombre de proyecto, navegación, colapso y expansión de información, controles de formulario con form-inline, cadenas de texto, etc. Nav: los elementos se muestran horizontalmente y alineados siempre que sea posible. Forms: permite aplicar controles de formulario con form-inline. Text: pueden contener texto. Color schemes: permite aplicar temas (fondos y colores para textos). Containers: se puede incluir un navbar en un container para centrarlo mejor. Placement: permite ubicar el navbar en diferentes posiciones de la página (top, bottom, sticky). Responsive behaviors: permite mostrar u ocultar elementos asociados a un botón cuando el tamaño de la pantalla cambia. Toggler: permite posicionar el botón a la derecha o a la izquierda. External content: permite ocultar información desplegando o colapsando información.

    En el siguiente ejercicio implementaremos algunos ejemplos de los que se muestran en la página de Bootstrap. 1. En primer lugar, nos ubicamos en Ej100_angular y creamos el proyecto btNavbar tecleando ng new btNavbar. 2. Seguidamente, renombraremos el proyecto para que haga referencia a nuestro número de ejercicio. Para ello, estando ubicados en el directorio Ej100_angular, escribiremos lo siguiente:

    442

    El gran libro de Angular

    C:\Ej100_angular>rename btNavbar 099_btNavbar

    Abrimos nuestro proyecto (por ejemplo, con Atom) y abrimos el archivo app.component.ts para modicar el título (title) y poner por ejemplo “099 Bootstrap btNavbar”. 3. Tal y como explicamos en el ejercicio anterior, instalaremos las librerías de forma local descargándolas e incorporándolas en el proyecto bajo la carpeta assets y también modicaremos el archivo angular-cli.json para hacer referencia a estas librerías. Por favor, revise el ejercicio 093 si tiene alguna duda. 4. A continuación, en nuestro archivo app. component.html añadiremos un elemento div con la clase container alrededor de nuestro title para que quede así:

    Importante Use Navbar para crear, por ejemplo, una barra de opciones para su aplicación que se adapte a cualquier dispositivo y ofrezca las opciones en forma de menú.

    {{title}}



    En la página de Bootstra /Navbar localizamos el primer ejemplo asociado a ed content y copiamos su contenido para pegarlo a continuación del cierre del tag que cierra nuestro title:

    {{title}}



    Guardaremos el archivo y arrancaremos la aplicación ubicándonos en C:\ Ej100_angular\099_btNavbar y tecleando ng serve. Observe el resultado en el navegador accediendo a el URL http://localhost:4200/.

    444

    El gran libro de Angular

    5. Ahora, reduzca el ancho de la página para comprobar cómo se ocultan las opciones y aparece un botón el cual, al pulsarlo, muestra las opciones verticalmente.

    6. A continuación, localizaremos el apartado Color schemes y modicaremos el tag

    Collapsed content

    <span class=”text-muted”>Toggleable via the navbar brand.
    ...

    Guardamos el archivo y vemos cómo se muestra en el navegador.

    446

    El gran libro de Angular

    9. Ahora, comprobamos cómo al pulsar sobre el botón, se muestra el contenido “oculto”. 10. Para comprobar cómo se adaptan los elementos a la pantalla cuando esta cambia de tamaño, reduzca al máximo y despliegue todos los bloques para ver cómo se muestra.

    El gran libro de Angular

    447

    100

    Bootstrap: Progress

    El componente Progress permite mostrar el avance Importante de un proceso visualizando una barra de progreso. Para añadir un valor a la barra, añadimos dicho valor al div La barra de progreso al que le hemos asociado la clase progress-bar. Poofrece información demos variar el alto de la barra con la propiedad heisobre el avance de una tarea de forma gráca ght mediante “style” (p. ej., style=”height: 1px;”). y simple. Podemos denir el background mediante las clases bg-success, bg-info, y mostrar varias barras simultáneamente solapadas entre sí y aplicando una animación mediante la clase progress-bar-animated. Veamos algún ejemplo de la página de Bootstrap (https://v4-alpha.getbootstrap.com/ components/progress/). 1. Nos ubicamos en Ej100_angular, y creamos el proyecto btProgress tecleando ng new btProgress. 2. Ahora, renombraremos el proyecto desde el directorio Ej100_angular, escribiendo lo siguiente: C:\Ej100_angular>rename btProgress 100_btProgress

    Abrimos el proyecto y en app.component.ts modicamos title con “100 Bootstrap Progress”. 3. Instalaremos las librerías localmente. Por favor, revise el ejercicio 093. 4. En app.component.html añadimos un div con la clase container alrededor de nuestro title así:

    {{title}}



    Localizamos el primer ejemplo de Progress, y copiamos el bloque que muestra el 25% para pegarlo en app.component.html detrás de para que el archivo quede de la siguiente manera:

    448

    El gran libro de Angular

    {{title}}



    Guardamos el archivo y arrancamos la aplicación desde C:\Ej100_angular\100_btProgress tecleando ng serve. Observe el resultado en el navegador en el URL http://localhost:4200/.

    5. A continuación, modicamos app.component.ts para que la clase AppComponent quede así: export class AppComponent { title = ‘100 Bootstrap Progress’; valorN: number = 20; valorT: string = “20%”; onChange($event) { this.valorN = parseInt($event.target.value); this.valorT = this.valorN + “%”; } }

    El evento para el input lo añadiremos a nuestra página así:

    El gran libro de Angular

    449

    {{title}}




    Hemos añadido un [ngStyle] para que el ancho (width) sea variable según el valor que se introduzca en el input y un evento “onChange()” para poder redibujar la barra de progreso. 6. Guardamos el archivo y probamos en el navegador con los valores 30 y 80.

    7. Añadimos el contenido de la variable valor modicando el div que contiene la clase progress-bar:
    {{ valorT }}


    Guardamos el archivo y vemos cómo queda en el navegador con el valor 50.

    450

    El gran libro de Angular

    8. Ahora añadiremos un par de botones para modicar el tamaño de la barra de progreso. Escogemos dos imágenes para echa arriba y abajo para aumentar y disminuir, respectivamente, dicho tamaño. 9. Creamos la carpeta src/images y en la misma ponemos las imágenes (p. ej., arriba.svg y abajo.svg).

    10. Seguidamente, incluimos las imágenes con el siguiente codigo detrás del tag input anterior:

    Click(‘+’)” > ””
    height=” 30”>


    Modicaremos la clase AppComponent en app.component.ts para que quede así: El gran libro de Angular

    451

    export class AppComponent { title = ‘100 Bootstrap Progress’; valor: string = “20”; valorN: number = 20; valorT: string = “20%”; incr: number = 1; onChange($event) { this.valorN = parseInt($event.target.value); this.valorT = this.valorN + “%”; } onClick(action: string) { console.log(“action “ + action); if (action == “+”) { this.incr = 1; } else { this.incr = -1; } this.valorN = parseInt(this.valor) + this.incr; if (this.valorN < 0) this.valorN = 0; if (this.valorN > 100) this.valorN = 100; this.valor = this.valorN.toString(); this.valorT = this.valorN + “%”; } }

    Probamos las echas y vemos como la barra aumenta o disminuye según pulsemos un botón u otro.

    11. Ahora, añadimos la clase progress-bar-striped al div que posee la clase progress-bar así:

    452

    El gran libro de Angular



    Guarde el archivo y observe cóomo queda.

    12. Por último, añadimos la clase progress-bar-animated y vemos cómo queda.

    Descargado en: ey books.com El gran libro de Angular

    453

    Related Documents


    More Documents from "Anonymous WNN7Hujl"

    Observe el resultado en el navegador. 11. Por último, pruebe las “Contextual clases” añadiendo a la primera la del tbody la clase table-success, para que quede de la siguiente manera: 384 El gran libro de Angular Compruebe el resultado en el navegador. 12. Pruebe con el resto de clases ofrecidas por la página para experimentar sobre las diferentes posibilidades que ofrece este tema. El gran libro de Angular 385 090 Bootstrap: Alerts En este ejercicio, presentaremos las alertas que podemos utilizar con Bootstrap de forma sencilla y practicaremos con algunas de las mismas. Al igual que comentamos en ejercicios anteriores y que se repetirá en los ejercicios relativos a Bootstrap, nos hemos de conectar a la página https://v4-alpha.getbootstrap.com/ y seleccionar la opción de menú Documentation. En dicha página, teclearemos en la caja de texto Search, el término Alerts, para seleccionar la opción propuesta y trasladarnos a la página en la que se explica su cometido y se ofrecen diferentes recursos para su uso. Vamos a crear un proyecto donde poder probar este tema. Para ello, haremos lo siguiente: 1. En primer lugar, nos ubicaremos en Ej100_ angular y crearemos el proyecto btAlerts tecleando ng new btAlerts. 2. Seguidamente, renombraremos el proyecto para que haga referencia a nuestro número de ejercicio. Para ello, estando ubicados en el directorio Ej100_angular, escribiremos lo siguiente: Importante Use las alertas cuando quiera mostrar una información temporalmente o un aviso. C:\Ej100_angular>rename btAlerts 090_btAlerts Ahora, abrimos nuestro proyecto con nuestro editor (en nuestro caso usamos Atom) y abrimos el archivo app.component.ts para modicar el título (title) y poner, por ejemplo, “090 Bootstrap Alerts”. 3. De la misma forma que explicamos en ejercicios anteriores, modicaremos nuestro archivo app.component.html para insertar al principio la línea que hace referencia a la hoja de estilos de Bootstrap: rel=”stylesheet” href=”https://maxcdn.bootstrapcdn. com/bootstrap/4.0.0- ... 4. Tras esta línea de referencia, comprobaremos que el resto de la página contiene lo siguiente: 386 El gran libro de Angular Y al nal del mismo archivo, comprobaremos las referencias a jquery, tether y bootstrap: <script src=”https://code.jquery.com/jquery ... Arrancamos la aplicación con ng serve y observamos cómo se ve nuestra aplicación en el navegador. 5. A continuación, acudimos a la página de Bootstrap y copiamos el primer ejemplo que contiene lo siguiente: Lo pegamos debajo del que cierra nuestro título, guardamos el archivo y vemos el resultado en el navegador. 6. Seguidamente, probamos el ejemplo que muestra una cabecera y un párrafo. En la página de Bootstrap, en Aditional content veremos lo siguiente: El gran libro de Angular 387 Lo copiamos (Copy) y lo pegamos a continuación de la alerta anterior en nuestra página HTML y modicamos alert-success por alert-info y vemos cómo queda en el navegador. 7. Si seguimos avanzando en la página, encontramos el apartado Dismissing donde veremos que la alerta puede cerrarse. Podemos copiar (Copy) el ejemplo y pegarlo en nuestra página HTML a continuación de la alerta anterior: Guardamos el archivo y vemos cómo queda en el navegador. Si pulsa sobre la cruz que aparece en la esquina superior derecha verá cómo se cierra la alerta. 8. Ahora, para que se vea mejor y quede mejor organizado, encerraremos nuestro título y nuestras alertas en un DIV que use la clase “container”: 388 El gran libro de Angular Veamos cómo se muestra en el navegador. 9. Por último, podemos añadir una alerta con un link localizando en la página el apartado Link color y copiando el primer ejemplo que posee el siguiente contenido: El gran libro de Angular 389 Lo pegamos detrás de la última alerta y modicamos el contenido para que contenga lo siguiente: Guardamos el archivo y acudimos al navegador para ver la nueva alerta (06) y observaremos que al pulsar sobre el link, se crea una nueva pestaña en la que se muestra la página del buscador de Google. 390 El gran libro de Angular 091 Bootstrap: Buttons y ButtonGroups En este capítulo, abordaremos los detalles relacionados con los Buttons y con los ButtonGroups que, aunque tengan un nombre parecido, realmente son controles diferentes. Importante Use las clases asociadas a los botones para darle un aspecto más agradable a los mismos y también para cambiar la visualización de tags como , , Checkbox y Radio buttons.

    Podemos encontrar información relativa a los buttons en la página de Bootstrap https://v4-alpha.getbootstrap.com/, tecleando la palabra Buttons en la caja de texto Search, existente en Documentation. Como siempre, en esta página encontraremos toda la información asociada a este tipo de elementos además de ejemplos y plantillas que nos agilizaran los desarrollos. Veremos que, por defecto, vienen una serie de estilos predenidos que son: Primary, Secondary, Success, Info, Warning, Danger y Link. Si seguimos curioseando la página, veremos aspectos como: • • • •

    Outline buttons: elimina las imágenes y colores de fondo que puedan traer los botones. Sizes: Para crear botones con diferentes tamaños (large, small, block). State: Para crear botones que estén habilitados o deshabilitados o que funcionen como un interruptor ON/OFF (Active, disabled, toggle). Etc.

    Ejercicio para Buttons En el siguiente ejercicio, crearemos una aplicación en la que simplemente mostraremos unos cuantos botones con diferentes estilos a los que no daremos funcionaEl gran libro de Angular

    391

    lidad, excepto al que lleva asociado un link, que lo usaremos para navegar a otra página. 1. En primer lugar, nos ubicaremos en Ej100_angular y crearemos el proyecto btButtonsB tecleando ng new btButtonsB. 2. Seguidamente, renombraremos el proyecto para que haga referencia a nuestro número de ejercicio. Para ello, estando ubicados en el directorio Ej100_angular, escribiremos lo siguiente: C:\Ej100_angular>rename btButtonsB 091_btButtonsB

    Ahora, abrimos nuestro proyecto con nuestro editor (en nuestro caso usamos Atom) y abrimos el archivo app.component.ts para modicar el título (title) y poner por ejemplo “091 Bootstrap ButtonsB”. 3. De la misma forma que explicamos en ejercicios anteriores, modicaremos nuestro archivo app.component.html para insertar al principio la línea que hace referencia a la hoja de estilos de Bootstrap:
    El resto del archivo contendrá lo siguiente:

    {{title}}



    Y al nal del mismo archivo, las referencias a jquery, tether y bootstrap: <script src=”https://code.jquery.com/jquery ...

    Añadiremos un elemento DIV con la clase “container” alrededor de nuestro

    que muestra el títle para que quede de la siguiente manera:

    {{title}}



    392

    El gran libro de Angular

    Arrancamos nuestra aplicación (con ng serve desde C:\Ej100_angular>091_btButtonsB) y observamos cómo se ve nuestra aplicación en el navegador.

    4. Seguidamente, desde la página de Bootstrap dedicada a los botones, copiaremos el primer ejemplo correspondiente al estilo ‘Primary’, que posee el siguiente contenido:

    asociado a title. Para organizar mejor los bloques, encerraremos este botón en un DIV al que le añadimos la clase “row “ para indicar que se trata de una la y m-2 para que añada un margen alrededor del botón (por favor, consulte el apartado Utilities->Spacing para más detalles). Queda de la siguiente manera:


    Guardamos el archivo y lo visualizamos en el navegador.

    5. Luego, localizamos en la página de Bootstrap el apartado Button tags y copiamos el ejemplo correspondiente al tag
    que usa las clases “btn …” y que concretamente contiene lo siguiente: El gran libro de Angular

    393

    Link Volvemos a nuestra página HTML y añadimos otro bloque DIV idéntico al del ejemplo anterior para colocar lo que hemos copiado, pero modicaremos la propiedad href para que apunte a “http://www.google.com” quedando de la siguiente manera: Guarde el archivo y observe cómo se ve en el navegador. Haga click sobre el botón Link y compruebe que navega hasta la página de Google. 6. Seguidamente, probaremos un ejemplo del apartado Outline buttons. Localícelo en la página y copie el ejemplo que posee el siguiente contenido: Inserte un DIV como los comentados anteriormente y dentro del mismo, pegue el contenido copiado. Guarde y compruebe el resultado en el navegador. 7. Por último, haremos una prueba con un botón grande y otro pequeño. Para ello, localice el apartado Sizes en la página de Bootstrap y copie los primeros ejemplos de Large button y Small button. Luego, cree un DIV para cada uno de ellos en nuestro archivo HTML de forma que al nal contenga lo siguiente: 394 El gran libro de Angular Guarde el archivo y compruebe cómo queda en el navegador. 8. Le animamos a que pruebe el resto de ejemplos de la página para comprobar el resultado ya que, experimentar, es una muy buena forma de aprender. ButtonGroup Importante Los Button group son elementos que permiten la creación de grupos de botones en una sola línea (o vaUse las clases asociadas rias) y que pueden modicar el aspecto también de a button group no checkbox y radio-buttons. Podemos encontrar la solo para botones información relativa a los button group en la págisino también para na de Bootstrap https://v4-alpha.getbootstrap.com/, checkbox y radio buttons si lo desea. tecleando en la caja de texto Search existente en Documentation, el texto button group. Como de costumbre, en la página hallaremos ejemplos, plantillas y, además, una explicación sobre posibles aspectos a tener en cuenta como, por ejemplo: • • Buttons toolbar: permite combinar grupos de botones en una barra de herramientas de botones Sizing: permite aplicar un tamaño estándar (btn-group-lg, btn-groupsm) a un grupo de botones en lugar de ir uno a uno. El gran libro de Angular 395 Nesting: es posible incluir grupos de botones anidados. Vertical variation: permite mostrar los botones de un grupo verticalmente. En el siguiente ejercicio veremos algunas de las funcionalidades expuestas en la página para que el lector tenga una pequeña experiencia con el tema. En primer lugar, crearemos un sencillo ejemplo de 3 radio buttons que devuelven 3 valores diferentes y que no usan de momento, ninguna clase especial de los button group. Posteriormente copiaremos un bloque de código de la página de Bootstrap y la adaptaremos para hacer la misma acción que la comentada en el ejemplo clásico. • • 1. Nos ubicamos en Ej100_angular y creamos el proyecto btBtGroupBG tecleando ng new btBtGroupBG. 2. Seguidamente, renombraremos el proyecto para que haga referencia a nuestro número de ejercicio. Para ello, estando ubicados en el directorio Ej100_angular, escribiremos lo siguiente: C:\Ej100_angular>rename btBtGroupBG 091_btBtGroupBG Abrimos nuestro proyecto (por ejemplo con Atom) y abrimos el archivo app.component.ts para modicar el título (title) y poner por ejemplo “091 Bootstrap Button Group”. 3. Igual que en ejercicios anteriores, modicaremos el archivo app. component.html para insertar al principio la línea que hace referencia a la hoja de estilos de Bootstrap: El resto del archivo contendrá lo siguiente: Y al nal del mismo archivo, las referencias a jquery, tether y bootstrap: <script src=”https://code.jquery.com/jquery ... Añadiremos un elemento DIV con la clase “container” alrededor de nuestro títle para que quede así: 396 El gran libro de Angular Arrancamos la aplicación (con ng serve desde C:\Ej100_angular>091_ btBtGroupBG) y observamos cómo se ve nuestra aplicación en el navegador. 4. A continuación, en nuestro archivo app.component.html añadiremos después de lo siguiente: Opción seleccionada: {{ res }} 5. Hemos incluido 3 radio buttons con un valor para cada uno y con una llamada al método onClick cuando hacemos un click. También visualizamos la variable res usando la interpolación ({{}}). 6. Ahora, en app.component.ts modicamos la clase AppComponent para que quede con lo siguiente: export class AppComponent { title = ‘091 Bootstrap Button Group’; res: string; onClick(event) { this.res = event.target.value; } } Al hacer un click sobre cualquier radio, se llamar al método onClick el cual, obtendrá el valor de la propiedad value y lo asignará a la variable res para que se muestre como la opción seleccionada. El gran libro de Angular 397 7. Guardamos el archivo y vemos cómo funciona en el navegador haciendo click sobre los radio buttons y observando cómo cambia el valor de la opción seleccionada. 8. Ahora, en la página dedicada a los Button group que indicamos al principio, localizamos el ejemplo básico y copiamos (Copy) su contenido para pegarlo antes de “Opción seleccionada”: Una vez copiado lo modicamos para adaptarlo al primer ejemplo y que quede de la siguiente manera: 398 El gran libro de Angular Guardamos el archivo y probamos su funcionamiento en el navegador. 9. Seguidamente, copiamos este mismo bloque y lo pegamos a continuación del que lo cierra. Añadamos también un para separar los bloques DIV y modiquemos la clase btn-group por btn-group-vertical para mostrar los botones verticalmente: … ) lo siguiente: 410 El gran libro de Angular Además de añadir un contenedor, un borde y un margen sobre el eje y (my2), veremos la conversión a minúsculas, mayúsculas y “capitalización” del texto. 7. Por último, localice el apartado Font weight and italics y copie su ejemplo (Copy) para pegarlo y envolverlo con un div (con la clase container y otro borde diferente) a continuación del bloque anterior para que quede de la siguiente manera: Guarde el archivo y observe cómo se ve en el navegador. El gran libro de Angular 411 8. Compruebe cómo se adapta el texto a los diferentes tamaños de pantalla. 412 El gran libro de Angular 094 Bootstrap: Carousel El carrusel es un elemento de Bootstrap que nos permite realizar presentaciones muy vistosas a través de la visualización de imágenes, texto y otros elementos de forma cíclica. Como de costumbre, en la página de Bootstrap dedicada a este tema (https://v4-alpha.getbootstrap.com/components/carousel/) encontraremos diversos ejemplos listos para ser copiados y pegados en nuestra página para poder adaptarlos posteriormente a nuestras necesidades con poco esfuerzo. Si analizamos la página nos encontraremos los siguientes temas: • • • • • Slides only: muestra solo diapositivas (una detrás de otra). With controls: añade controles para desplazarnos por las diapositivas anterior y posterior. With indicators: con elementos que nos permiten desplazarnos directamente a una diapositiva en concreto. With captions: permite añadir subtítulos que pueden mostrarse o no en función del tamaño de la vista. Usage: opciones que permiten determinar la posición del carrusel, la velocidad de transición de una diapositiva a otra, si ha de reaccionar a eventos de teclado, etc. A continuación, vamos a realizar un ejercicio en el que veremos algunos ejemplos de los descritos en la página. 1. En primer lugar, nos ubicamos en Ej100_angular y creamos el proyecto btCarousel tecleando ng new btCarousel. 2. Seguidamente, renombraremos el proyecto para que haga referencia a nuestro número de ejercicio. Para ello, estando ubicados en el directorio Ej100_angular, escribiremos lo siguiente: C:\Ej100_angular>rename btCarousel 094_btCarousel Abrimos nuestro proyecto (por ejemplo, con Atom) y abrimos el archivo app.component.ts para modicar el título (title) y poner por ejemplo “094 Bootstrap Carousel”. El gran libro de Angular 413 3. Tal y como explicamos en el ejercicio anterior, instalaremos las librerías de forma local descargándolas e incorporándolas en el proyecto bajo la carpeta assets. Si ha realizado el ejercicio anterior, puede copiar la carpeta assets y pegarla bajo src de este mismo ejercicio. No olvide modicar el archivo angular-cli.json para hacer referencia a estas librerías tal y como se explicó. Importante Cree presentaciones vistosas copiando y pegando el código ofrecido por Bootstrap y acelere la fabricación de vistas dejando que las clases de Bootstrap hagan el trabajo. 4. A continuación, en nuestro archivo app.component.html añadiremos un elemento div con la clase container alrededor de nuestro title para que quede así: Para este ejercicio, necesitaremos tres imágenes (p. ej., img1.jpg, img2.jpg e img3.jpg) que depositaremos en una nueva carpeta llamada images que crearemos bajo src. Procure que sean imágenes de un cierto tamaño para que al mostrarlas en pantalla grande se vean bien. 5. En la página de Bootstrap/Carousel (https://v4alpha.getbootstrap.com/components/carousel/) localizamos el ejemplo que muestra bajo el apartado With controls y copiamos su contenido para pegarlo a continuación del cierre del tag que cierra nuestro title: 414 El gran libro de Angular … … Ahora, modicaremos las propiedades src de cada imagen para que apunten a la ubicación de nuestras imágenes y añadiremos la clase w-100 a las clases del tag img de la siguiente manera: El gran libro de Angular 415 Para las imágenes 2 y 3 realizaremos la misma operación. Guardaremos el archivo y arrancaremos la aplicación ubicándonos en C:\Ej100_angular\094_btCarousel y tecleando ng serve. Observe el resultado en el navegador accediendo a el URL http://localhost:4200/. 6. Pulse sobre las echas laterales para provocar la visualización de las imágenes. Si no las pulsa, estas se irán visualizando cada cierto tiempo. 7. Varíe el tamaño de la página para comprobar cómo la visualización se adapta en cada momento. 8. A continuación, vamos a probar otro ejemplo similar, pero algo más completo. Para ello, localizaremos un poco más abajo, en la misma página de Bootstrap, 416 El gran libro de Angular el apartado With indicators y copiaremos (Copy) su contenido para pegarlo en nuestra página app.component.html a continuación del que cierra nuestro carrusel anterior: … … Al igual que en el caso anterior, modicaremos los tags correspondientes a las imágenes para que apunten a las ubicaciones de nuestro proyecto y contengan la clase w-100: Para separar un carrusel de otro, añadiremos la clase my-2 para incluir un margen en el eje y (verticalmente) y un borde al bloque. La primera línea de nuestro carrusel quedará así: . La idea, en este caso, es que el botón copiado relacionado con el tag Guardamos el archivo y lo visualizamos en nuestro navegador. 9. Si pulsamos cualquiera de los botones “Uno Con Ref” o “Uno con Boton”, aparece el bloque con el texto “Mi bloque uno” con los dos botones incluidos en el mismo. El gran libro de Angular 423 10. Si pulsamos el botón “Dos Con Ref”, veremos el bloque “dos” asociado al mismo. 11. Si pulsamos el botón “Tres con boton”, veremos el bloque “tres” asociado al mismo. 12. A partir de aquí, le invitamos a que pruebe cualquier combinación de pulsación de botones para ver cómo se comporta la visualización en función de su anidamiento. 424 El gran libro de Angular 096 Bootstrap: Dropdowns Los Dropdowns son elementos que se despliegan de forma interactiva y que permiten mostrar listas de elementos como, por ejemplo, vínculos mediante los cuales se pueden realizar selecciones o acciones. Si analizamos la página de Bootstrap dedicada a Dropdowns (https://v4-alpha.getbootstrap.com/components/dropdowns/), veremos que hace referencia a diferentes temas relacionados con: • • • • • • • • Diferentes tipos de botones: sencillos, separando la echa del elemento en un botón aparte. Sizing: para botones pequeños (small) y grandes (large). Dropup variation: para que el despliegue de la lista se haga hacia arriba. Menu items: ofrece el uso de botones en lugar de links para las opciones. Menu alignment: permite alinear el despliegue de opciones a la derecha. Menu headers: inserción de cabeceras en la lista. Menu dividers: inclusión de divisores en la lista. Disabled menu items: deshabilita ítems de una lista. Importante Como alternativa a la organización de opciones, puede disponer de listas desplegables a las que puede asociar a links o botones y realizar acciones de forma sencilla. En el siguiente ejercicio, adaptaremos uno de los ejemplos de dicha página para seleccionar un color de la lista y aplicarlo a un bloque que muestra el resultado seleccionado. 1. Ubicados en Ej100_angular, creamos el proyecto btDropDown tecleando ng new btDropDown. 2. Ahora, renombraremos el proyecto desde el directorio Ej100_angular, escribiendo lo siguiente: C:\Ej100_angular>rename btDropDown 096_btDropDown Abrimos el proyecto y en app.component.ts modicamos title con “096 Bootstrap btDropDown”. 3. Instalaremos las librerías localmente. Por favor, revise el ejercicio 093. El gran libro de Angular 425 4. En app.component.html añadimos un div con la clase container alrededor de nuestro title así: Localizamos el primer ejemplo de Dropdowns, y lo pegamos en app.component.html detrás de :