Angular e Book
Angular e Book
SAPiens IT
Pedro Jiménez Castela
Angular 4 desde Cero
La guía básica de introducción a este
poderoso framework.
¡Este es tu curso!
www.sapienslearning.com
SAPiens IT
Índice
Página 1
5.7 Utilización de @Input entre componentes 79
5.8 Utilización de @Output entre componentes 84
Página 2
Página 3
Introducción
¡Hola! Mi nombre es Pedro y he escrito este libro para que aprendas de manera
práctica el increíble framework Angular, que nos permite crear aplicaciones
modernas en la nube, con todos los requisitos que demandan las empresas más
exigentes.
Página 4
1 TypeScript y Web Components
1.1 TypeScript
Página 5
1.2 Instalación de TypeScript
tsc -v
Que nos devolverá la versión instalada y así tendremos nuestro equipo listo para
trabajar.
Página 6
1.3 Tipos de datos en TypeScript
• Strings
• Números
• Arrays.
Página 7
• Any
• Booleanos.
https://www.typescriptlang.org/docs/handbook/basic-types.html.
Si quieres utilizar Visual Studio Code, mi editor favorito, al final del libro
aprendemos a instalarlo y configurarlo.
index.html
<!DOCTYPE html>
<html lang="es">
<head>
<title></title>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1"
</head>
Página 8
<body>
<h1 id="encabezado"></h1> ①
<script type="text/javascript" src="test.js"></script> ②
</body>
</html>
En el cual:
test.ts
function saludo(nombre){
return "Hola "+nombre; ②
}
document.getElementById("encabezado").innerHTML = saludo(nombre); ③
En el cual:
Página 9
Para ello, en la consola de nuestro equipo, dentro de la carpeta typetest
tecleamos:
tsc test.ts
tsc –w test.ts
test.ts
function imprPantalla(a,b){
return a+b;
}
let b: number = 5;
document.getElementById("encabezado").innerHTML = imprPantalla(a,b);
Página 10
Lógicamente este código imprimirá por pantalla el número 15. Pero si ahora
modificamos:
Página 11
1.4 Variables en TypeScript
Pero además, TypeScript permite también emplear la palabra reserva var como
en JavaScript, entonces… ¿cuándo emplear una u otra forma?
test.ts
let a = 10; ①
if (true){
let a = 15 ②
console.log("Dentro del if a tiene un valor de "+a);
} else {
//
}
En el cual:
Página 12
Comprobaremos en la consola del navegador, como arroja dos valores
diferentes de acuerdo al código que hemos programado:
test.ts
var a = 10;
if (true){
var a = 15
console.log("Dentro del if a tiene un valor de "+a);
} else {
//
}
Como la variable pasa a ser global, su valor dentro del if también se utiliza fuera
de esta y por tanto ambos logs muestran el mismo valor en la consola.
Página 13
1.5 Clases en TypeScript
class NombreClase {
public/private nombrepropiedad: tipo de dato;
….
public/private nombremetodo() {
//código del método
}
…
}
Por ejemplo, en nuestro archivo test.ts sustituimos todo el código para añadir:
test.ts
class Curso {
public titulo: string; ①
public descripcion: string;
public horas: number;
public inscritos: number;
public getInscritos() { ②
return this.inscritos;
}
public addInscrito(){
this.inscritos++;
}
Página 14
public remInscrito() {
this.inscritos--;
}
cursoAngular.setInscritos(9);
cursoAngular.addInscrito();
console.log(cursoAngular.getInscritos()); ④
En el cual:
Página 15
1.6 Constructor en TypeScript
La sintaxis es la siguiente:
class NombreClase {
public/private nombrepropiedad: tipo de dato;
….
constructor () {
this.nombrepropiedad = valor;
…
}
public/private nombremetodo() {
//código del método
}
…
}
Por ejemplo, podemos sustituir la clase anterior Curso por el siguiente código:
test.ts
class Curso {
public titulo: string;
public descripcion: string;
public horas: number;
public inscritos: number;
}
constructor() {
this.titulo = "Nombre del curso";
this.descripcion = "Lorem ipsum";
this.horas = 20;
this.inscritos = 0;
}
Página 16
public getInscritos() {
return this.inscritos;
}
public addInscrito(){
this.inscritos++;
}
public remInscrito() {
this.inscritos--;
}
console.log(cursoAngular);
Página 17
También podemos emplear parámetros en el constructor. Para ello modificamos
por ejemplo el constructor de la siguiente forma.
…
constructor( titulo, descripcion, horas ) {
this.titulo = titulo;
this.descripcion = descripcion;
this.horas = horas;
this.inscritos = 0; //en este caso se establecerán con el método
}
…
…
var cursoAngular = new Curso("Curso Angular","Lorem...",100);
…
De esta forma, el objeto se crea con los parámetros introducidos para cada
propiedad.
Página 18
1.7 Interfaces en TypeScript
Las interfaces, nos permitirán obligar a definir clases con unas determinadas
propiedades o métodos.
Su sintaxis es:
interface NombreInterfaz {
nombrepropiedad: tipodedato;
nombreMetodo(): tipodedato;
Y se implementan en la clase:
test.ts
interface DatosMaestros {
titulo: string;
addInscrito();
}
…
…
class Curso implements DatosMaestros {
…
}
Página 19
Y eliminamos la propiedad titulo en el constructor:
…
constructor( descripcion, horas ) {
this.descripcion = descripcion;
this.horas = horas;
this.inscritos = 0; //en este caso se establecerán con el método
}
…
https://www.typescriptlang.org/docs/home.html
Página 20
1.8 Web Components
Los web components son un estándar del W3C, que permiten componer el
desarrollo de aplicaciones web a partir de contenedores dedicados a una cierta
funcionalidad. Estarán compuestos por archivos con el lenguaje de marcado
HTML5, con código JavaScript para la lógica de negocio y con hojas de estilo
CSS para la presentación.
<nombre-del-componente></nombre-del-componente>
Angular, desde su primera versión a la actual, utiliza los web components como
tecnología para el desarrollo de aplicaciones web, como veremos a lo largo de
todo el libro.
https://developer.mozilla.org/es/docs/Web/Web_Components
Página 21
2. Configuración de proyectos: Angular-Cli
2.1 Instalación
Página 22
2.2 Requisitos Previos
node –v
npm –v
Página 23
2.4 Creación de un Proyecto en Angular
Una vez instalado Angular CLI, para crear un nuevo proyecto, nos situamos en
el directorio en el que queremos crear el proyecto en la consola y tecleamos:
ng new appCurso
cd appCurso
También podemos comprobar la estructura del proyecto creada por Angular CLI
en el editor que empleemos para el desarrollo de nuestra aplicación.
Página 24
También nos podemos fijar como a partir de este package.json, se ha creado
una carpeta de módulos Node JS denominada node_modules, que contiene
todo el código del framework Angular en forma de paquetes, que emplearemos
en nuestra aplicación.
Por último, disponemos de un directorio src (por source) donde estará el código
de nuestra aplicación. El resto de archivos y directorios serán tratados más
adelante.
Página 25
2.5 Arranque de la Aplicación
ng serve
localhost:4200
Página 26
2.6 El Archivo index.html
Además del código habitual de un archivo html, este archivo se caracteriza por
incluir la etiqueta <app-root></app-root>, que será la etiqueta del web
component donde se ‘renderice’ todo el código de la aplicación.
Dentro de la etiqueta raíz anterior, podemos añadir un texto que indique que la
aplicación está cargando o bien un spinner, que se mostrará durante la carga de
la aplicación si esta se demora.
Por ejemplo:
src/index.html
…
<app-root><p>Cargando aplicación…</p></app-root>
…
Si la aplicación es muy ligera, cargará tan rápido el componente raíz, que ese
texto de carga, directamente no se mostrará.
Por ejemplo, nosotros vamos a emplear las fuentes Google y Bootstrap 4, para
lo cual añadimos, dentro del <head></head>:
…
<link href="https://fonts.googleapis.com/css?family=Open+Sans"
rel="stylesheet">
<link rel="stylesheet"
href="https://maxcdn.bootstrapcdn.com/bootstrap/4.0.0-
alpha.6/css/bootstrap.min.css" integrity="sha384-
Página 27
rwoIResjU2yc3z8GV/NPeZWAv56rSmLldC3R/AZzGRnGxQQKnKkoFVhFQhNU
wEyJ" crossorigin="anonymous">
<script src="https://code.jquery.com/jquery-3.1.1.slim.min.js"
integrity="sha384-
A7FZj7v+d/sdmMqp/nOQwliLvUsJfDHW+k9Omg/a/EheAdgtzNs3hpfag6Ed95
0n" crossorigin="anonymous"></script>
<script
src="https://cdnjs.cloudflare.com/ajax/libs/tether/1.4.0/js/tether.min.js"
integrity="sha384-
DztdAPBWPRXSA/3eYEEUWrWCy7G5KFbe8fFjk5JAIxUYHKkDx6Qin1DkWx51
bBrb" crossorigin="anonymous"></script>
<script src="https://maxcdn.bootstrapcdn.com/bootstrap/4.0.0-
alpha.6/js/bootstrap.min.js" integrity="sha384-
vBWWzlZJ8ea9aCX4pEW3rVHjgjt7zpkNpZk+02D9phzyeVkE+jo0ieGizqPLForn
" crossorigin="anonymous"></script>
…
.angular-cli.json
…
styles: [
“../node_modules/bootstrap/dist/css/bootstrap.min.css”,
“styles.css”
]
…
Página 28
2.7 El Archivo styles.css
http://www.genfavicon.com/es/
Página 29
3 Módulos y Componentes
Página 30
1. En primer lugar una serie de instrucciones de importación de las librerías
o paquetes Angular, asi como otros elementos externos que
emplearemos en el módulo.
Página 31
Si nos fijamos en el código del archivo app.module.ts está compuesto de los
tres bloques de código detallados en el párrafo anterior.
src/app/app.module.ts
@NgModule({
declarations: [
AppComponent
], ②
imports: [
BrowserModule,
FormsModule
],
providers: [],
bootstrap: [AppComponent]
})
Página 32
• Y bootstrap, recordamos exclusivo de este módulo raíz, que define el
componente AppComponent para inicializar la aplicación.
Podemos definir un componente como una clase Angular que controla una parte
de la aplicación, de ahí que sean englobados como un tipo de vista.
Página 33
src/app/app.component.ts
@Component({
selector: 'app-root',
templateUrl: './app.component.html', ②
styleUrls: ['./app.component.css']
})
En el cual:
Página 34
Veamos a continuación el funcionamiento del componente incluido en el
módulo raíz.
src/app/app.component.html
<div style="text-align:center">
<h1>
Welcome to {{title}}!!
</h1>
<img width="300" src="…” />
</div>
<h2>Here are some links to help you start: </h2>
<ul>
<li>
<h2><a target="_blank"
href="https://angular.io/docs/ts/latest/tutorial/">Tour of Heroes</a></h2>
</li>
<li>
…
</li>
</ul>
Vemos como se trata de un archivo html pero sin la estructura de página web,
ya que se inyectará en en el archivo index.html. Además de las etiquetas html y
los textos, el código incorpora la variable title mediante la sintaxis moustache {{
title }}, de tal forma que esta sintaxis lo enlaza componente y mostrará en
pantalla el valor definido en la clase de este.
Página 35
Repetimos que el componente se exporta mediante la clase AppComponent,
que es importada en el módulo app.module.ts e incluida dentro de su decorador
en las declaraciones:
src/app/app.module.ts
…
import { AppComponent } from './app.component';
…
…
declarations: [
AppComponent
],
…
Por otra parte, este archivo de módulo app.module.ts es el módulo raíz e incluye
en el decorador la propiedad Bootstrap igualada al componente, para
finalmente exportar todo el módulo con la clase AppModule:
bootstrap: [AppComponent]
})
export class AppModule { }
¿Dónde empleamos esta clase del módulo que se exporta? En otro archivo
situado en la raíz de la aplicación, denominado main.ts.
src/main.ts
Página 36
if (environment.production) {
enableProdMode();
}
platformBrowserDynamic().bootstrapModule(AppModule); ②
src/index.html
…
<body>
<app-root></app-root>
</body>
…
Página 37
Otra forma práctica de comprobarlo, es sustituir totalmente el contenido del
archivo app.component.html por un mítico ‘¡Hola Mundo!’:
src/app/app.component.html
<div style="text-align:center">
<h1>¡Hola Mundo!</h1>
</div>
src/app/app.component.ts
…
export class AppComponent {
destino: string = 'Universo';
}
…
src/app/app.component.html
<div style="text-align:center">
<h1>¡Hola {{ destino }}!</h1>
</div>
Página 38
Volvemos al navegador y comprobamos:
También podemos hacer uso del archivo de estilos CSS del componente,
app.component.ts, en el que por ejemplo escribir la siguiente clase:
src/app/app.component.css
.encabezado {
text-align: center;
color: blueviolet;
}
src/app/app.component.html
<div class="encabezado">
<h1>¡Hola {{ destino }}!</h1>
</div>
Página 39
3.3 Creación de un nuevo componente
Aunque se pueden crear con Angular CLI, para crear un nuevo componente de
manera manual, en primer lugar creamos un directorio con el nombre
identificativo del componente, por ejemplo, fechaactual, en el directorio src/app
de la aplicación.
src/app/fechaactual/fechaactual.component.ts
@Component({
selector: 'app-fechaactual', ①
templateUrl: './fechaactual.component.html' ②
Página 40
})
src/app/fechaactual/fechaactual.component.html
src/app/app.module.ts
…
import { FechaactualComponent } from './fechaactual/fechaactual.component'; ①
…
Página 41
…
declarations: [
AppComponent,
FechaactualComponent ②
],
…
Con esto, nuestro componente queda listo para ser utilizado, y por tanto
tenemos que añadir la etiqueta <app-fechaactual> donde queramos que se
renderice.
src/app/app.component.html
<div class="encabezado">
<h1>¡Hola {{ destino }}!</h1>
<app-fechaactual></app-fechaactual>
</div>
Página 42
Si el código html de la vista del componente es pequeño, como es nuestro caso,
podemos simplificar la aplicación, eliminando el archivo
fechactual.component.html, añadiendo el código de este en el componente
mediante el metadado template.
src/app/fechaactual/fechaactual.component.ts
@Component({
selector: 'app-fechaactual',
template: `
<p> Sevilla, {{ hoy | date:'d/M/y H:m'}}</p>
`
})
Página 43
3.4 Creación de componente con Angular CLI
Una de las funcionalidades de Angular CLI es la de generar los archivos de, entre
otros, un componente, evitándonos tener que escribir el código común como
hicimos en el apartado anterior.
o su versión abreviada:
ng g c <nombredelcomponente>
Página 44
src/app/copyright/copyright.component.ts
constructor() { }
ngOnInit() {
}
Más adelante hablaremos del método ngOnInit y del uso del constructor
JavaScript en Angular.
src/app/copyright/copyright.component.html
src/app/app.component.html
Página 45
Podemos comprobar en el navegador la correcta implementación del
componente.
Página 46
3.5 Anidado de Componentes
Por ejemplo dentro del template del componente copyright, podemos sustituir
el código para incluir la etiqueta del componente fechaactual:
src/app/copyright/copyright.component.html
<app-fechaactual></app-fechaactual>
<p> {{ copyright }} {{ hoy | date:'y'}} </p>
src/app/app.component.html
Página 47
src/app/copyright/copyright.component.html
src/app/fechaactual/ fechaactual.component.ts
…
@Component({
selector: 'app-fechaactual',
template: `
<p> Sevilla, {{ hoy | date:'d/M/y H:m'}}</p>
<app-copyright></app-copyright>
`
})
…
src/app/app.component.html
Página 48
El resultado en el navegador vuelve a ser de nuevo el mismo, por lo que
comprobamos que disponemos en Angular de la máxima flexibilidad a la hora
de estructurar los diferentes componentes de la aplicación.
Página 49
4 Data Binding
En primer lugar tenemos los data binding de tipo One Way de la fuente de datos
(archivo TypeScript) a la vista (archivo HTML). Dentro de este tipo se incluyen:
• Interpolación.
• Property Binding.
• Event Binding.
• Two-way Binding.
Página 50
4.1 Interpolación
{{ propiedad/objeto/expresión }}
Vamos a crear una clase que se pueda utilizar en toda la aplicación. En primer
lugar creamos un directorio llamado modelos en el directorio app de la
aplicación.
Página 51
src/app/modelos/alumno.modelo.ts
}
}
En el cual:
Página 52
Dentro de la clase de este nuevo componente en el archivo
viewmodelo.component.ts, importamos la clase Alumno y creamos un objeto
de esta clase llamado alumno1, de la siguiente manera:
src/app/viewmodelo/viewmodelo.component.ts
…
import { Alumno } from '../modelos/alumno.model';
…
…
export class ViewmodeloComponent {
alumno1 = new Alumno (1, 'Juan', 'Gutiérrez', 'Madrid'); } …
src/app/viewmodelo/viewmodelo.component.html
<div class="container">
<h4>Información del Alumno</h4>
<hr>
<h5>id: {{ alumno1.id }}</h5>
<hr>
<h5>Nombre: {{ alumno1.nombre }}</h5>
<hr>
<h5>Apellidos: {{ alumno1.apellidos }}</h5>
<hr>
<h5>Ciudad: {{ alumno1.ciudad }}</h5>
<hr>
</div>
Página 53
En el que empleamos, dentro de la interpolación, la sintaxis de la notación del
punto JavaScript para mostrar el valor de la propiedad de un objeto:
nombredelobjeto.propiedaddelobjeto
src/app/app.component.html
Página 54
Y una vez creado, añadimos a la clase del componente en
ejmetodo.component.ts el siguiente código:
src/app/ejmetodo/ejmetodo.component.ts
…
puntuacion = 9;
getPuntuacion() {
return this.puntuacion;
}
…
src/app/ejmetodo/ejmetodo.component.html
src/app/app.component.html
Página 55
Comprobamos en el navegador como se carga correctamente:
Página 56
4.2 Property Binding
En este caso, se trata de un enlace que relaciona un atributo con una expresión,
con la siguiente sintaxis:
[ atributodelelementoHTML ] = “ expresión “
src/app/ejpropertybinding/ejpropertybinding.component.html
src/app/app.component.html
Página 57
Hasta ahora nada de particular, pero vamos a ver cómo modificar el
comportamiento del atributo placeholder de manera dinámica mediante
property binding.
src/app/ejpropertybinding/ejpropertybinding.component.ts
…
texto = 'Escribe algo'; ①
constructor() {
setTimeout(() => {
this.texto = 'por favor'; ②
}, 3000);
}
src/app/ejpropertybinding/ejpropertybinding.component.html
Página 58
Y comprobaremos como, al iniciar el navegador, el input tendrá el texto “Escribe
algo” en su placeholder, y cuando transcurran 3 segundos, pasará a ser “por
favor”.
Página 59
4.3 Event Binding
Los enlaces event binding son enlaces de un solo sentido, one way, pero en este
caso desde la vista a la fuente de datos, ya que como su nombre indica, los
desencadena un evento en el cliente web.
evento=”nombreMetodo()”;
src/app/ejeventbinding/ejeventbinding.component.html
En el cual:
Página 60
Ahora, en el componente, archivo ejeventbinding.component.ts, añadimos el
siguiente código dentro de la clase:
src/app/ejeventbinding/ejeventbinding.component.ts
…
texto = 'Originalmente el texto se carga así';
modTexto() {
this.texto = 'Al pulsar el botón el texto se muestra así';
}
ngOnInit() {
}
…
src/app/app.component.html
Página 61
4.4 Two Way Binding
Para finalizar, disponemos de los enlaces two way binding, que enlazan en
ambos sentidos y simultáneamente, los datos de la vista a la fuente de datos y
viceversa.
[( directiva )] = “nombredelapropiedad”
Vamos a crear el último ejemplo de esta serie. Para ello, tecleamos desde la
consola del equipo en el directorio raíz de la aplicación:
src/app/ej2waybinding/ej2waybinding.component.html
<label>Introduce un valor</label>
<input type="text" class="form-control" [(ngModel)]="texto">
<h3>{{texto}}</h3>
FormsModule
Página 62
A continuación, en la clase del archivo ej2waybinding.component.ts añadimos
simplemente la declaración de la variable, con un valor de ejemplo.
src/app/ej2waybinding/ej2waybinding.component.ts
…
texto = 'Texto original al cargar';
constructor() { }
ngOnInit() {
}
…
src/app/app.component.html
Página 63
5 Directivas
Las directivas son clases Angular con instrucciones para crear, formatear e
interaccionar con los elementos HTML en el DOM, y son una de las principales
características de este framework.
Página 64
5.1 Directiva ngIf
*ngIf=”expresión/propiedad/metodo”
src/app/ejdirecivangif/ejdirecivangif.component.html
<div class="container">
<label>Nombre y Apellidos</label>
<input type="text"
class="form-control" ①
[(ngModel)]="nombre"
placeholder="Complete su nombre y apellidos">
<button type="submit" class="btn btn-primary" ②
*ngIf="nombre">Enviar</button>
</div>
En el cual:
Página 65
En la clase del componente en el archivo ejdirectivangif.component.ts
simplemente declaramos la propiedad nombre:
src/app/ejdirecivangif/ejdirecivangif.component.ts
nombre: string;
src/app/app.component.html
La directiva *ngIf se completa con el uso de else para resolver qué ocurre cuando
no se cumpla la condición. Para ello se añade la etiqueta ng-template, con el
contenido que necesitemos y se asocia una id de esa etiqueta a la palabra
reservada else en la misma expresión de *ngIf.
Página 66
Vamos a comprobarlo con nuestro ejemplo. Sustituimos todo el código de
nuestro archivo ejdirecivangif.component.html por el siguiente:
src/app/ejdirecivangif/ejdirecivangif.component.html
<label>Nombre y Apellidos</label>
<input type="text" class="form-control" [(ngModel)]="nombre"
placeholder="Complete su nombre y apellidos">
<button type="submit" class="btn btn-primary" *ngIf="nombre; else
desactivado">Enviar</button> ①
<ng-template #desactivado> ②
<button type="submit"
class="btn btn-primary"
disabled>Enviar</button>
</ng-template>
En el cual:
Página 67
La directiva *ngIf también permite el empleo de métodos para realizar
funcionalidades con una lógica definida en el componente.
src/app/ejdirecivangif/ejdirecivangif.component.html
En en el cual:
Página 68
src/app/ejdirecivangif/ejdirecivangif.component.ts
capital: string; ①
constructor() {
}
ngOnInit() {
}
setResultado(){
return this.capital === "Madrid" ? true : false; ②
}
En el cual:
Página 69
5.2 Directiva ngStyle
Su sintaxis es básicamente:
[ngStyle]=”{ expresión/propiedad/método }”
src/app/ejdirectivangstyle/ejdirectivangstyle.component.html
En el cual:
Página 70
Ahora en la clase del componente en el archivo ejdirectivangstyle.component.ts
añadimos:
src/app/ejdirectivangstyle/ejdirectivangstyle.component.ts
puntuacion: number;
constructor() {
}
ngOnInit() {
}
setColor() {
return this.puntuacion >= 5 ? 'green' : 'red'; ①
}
En el cual además de declarar la propiedad puntuación de tipo número,
añadimos ① el método setColor().
src/app/app.component.html
Página 71
De esta manera, ahora se mostrará en el navegador:
Página 72
5.3 Directiva ngClass
src/app/ejdirectivangclass/ejdirectivangclass.component.html
① Se crea un div con la directiva ngIf para que se muestre en el momento que
se introduzca una puntuación.
Página 73
③ En caso de que la puntuación no estuviera en el rango anterior, el ng-
template proporciona dos opciones, si estuviera por encima de diez, avisa para
introducir un valor menor y si estuviera por debajo de cero, avisa para introducir
un valor mayor, siendo la clase CSS en ambos casos, advertencia.
Como hemos añadido clases CSS en la plantilla, las añadimos en nuestro archivo
ejdirectivangclass.component.css de la siguiente manera:
src/app/ejdirectivangclass/ejdirectivangclass.component.css
.advertencia {
color: white;
background-color: orange;
padding: 10px;
}
.aprobado {
color: white;
background-color: green;
padding: 10px;
}
.suspenso {
color: white;
background-color: red;
padding: 10px;
}
src/app/ejdirectivangclass/ejdirectivangclass.component.ts
puntuacion: number;
Página 74
Y la etiqueta del componente en app.component.html:
src/app/app.component.html
Página 75
5.4 Directiva ngFor
En esta sintaxis, se crea dentro del elemento html una variable local con let que
recorrerá el array definido por of y proveniente del componente. Como buena
práctica, el nombre de la variable local será singular y el del array plural.
ng g c ejdirectivangfor -spec
src/app/ejdirectivangfor/ejdirectivangfor.component.ts
cursos: string[];
constructor() {
this.cursos = ['Angular', 'HTML', 'CSS'];
}
ngOnInit() {
}
Página 76
Y en la plantilla, ejdirectivangfor.component.html, implementamos la directiva
de la siguiente manera.
src/app/ejdirectivangfor/ejdirectivangfor.component.html
<h3>Cursos Disponibles</h3>
<ul>
① <li *ngFor="let curso of cursos"> ②<h4>{{curso}}</h4></li>
</ul>
En la cual:
src/app/app.component.html
Página 77
Otra de las formas habituales de empleo de la directiva ngFor es iterar un array
de objetos JSON, la forma estandarizada de objetos JavaScript que utilizan las
bases de datos NoSQL basadas en JavaScript.
nombredelarray: Array<nombredelaclase>;
ng g c arrayobjetos
src/app/arrayobjetos/arrayobjetos.component.ts
…
import { Alumno } from 'app/modelos/alumno.model';
…
…
public alumnos: Array<Alumno> = [
{id: 1 , nombre: 'Juan', apellidos: 'Gutierrez', ciudad: 'Madrid'},
{id: 2 , nombre: 'Pedro', apellidos: 'Lopez', ciudad: 'Sevilla'}
];
…
Página 78
Ahora, en la plantilla del componente, en el archivo
arrayobjetos.component.html añadimos el código html de una tabla en la que
iteramos en sus filas el array alumnos con la directiva ngFor:
src/app/arrayobjetos/arrayobjetos.component.html
src/app/app.component.html
Página 79
Y comprobamos en el navegador:
Página 80
5.5 Directiva NgSwitch
Vamos a ver un ejemplo, para lo cual como venimos haciendo, vamos a crear un
nuevo componente en la consola del equipo en la raíz del proyecto:
ng g c ejdirectivangswitch
En primer lugar vamos a crear un array de objetos simples (sin modelo) con
formato de documentos JSON en la clase del componente. Para ello, en el
archivo ejdirectivangswitch.component.ts incoporamos en la clase:
src/app/ejdirectivangswitch/ejdirectivangswitch.component.ts
jugadores: any[] = [
{ nombre: 'Earvin Jhonson', equipo: 'L.A. Lakers'},
{ nombre: 'Larry Bird', equipo: 'Boston Celtics'},
{ nombre: 'Michael Jordan', equipo: 'Chicago Bulls'}
]
src/app/ejdirectivangswitch/ejdirectivangswitch.component.html
Página 81
Y sustituimos la etiqueta en el archivo app.component.html por la de este
componente:
src/app/app.component.html
src/app/ejdirectivangswitch/ejdirectivangswitch.component.ts
<div class="text-center">
<ul *ngFor="let jugador of jugadores" [ngSwitch]="jugador.equipo"> ①
<li *ngSwitchCase="'L.A. Lakers'"
class="lakers"><h3>{{jugador.nombre}}</h3><h3 class="equipo"> {{ ②
jugador.equipo}} </h3></li>
<li *ngSwitchCase="'Boston Celtics'"
class="celtics"><h3>{{jugador.nombre}}</h3><h3 class="equipo"> {{
jugador.equipo}} </h3></li>
<li *ngSwitchCase="'Chicago Bulls'"
class="bulls"><h3>{{jugador.nombre}}</h3><h3 class="equipo"> {{
jugador.equipo}} </h3></li>
</ul>
</div>
Página 82
En el cual:
② Creamos tres etiquetas li, una por cada valor individual de la propiedad
equipo, y en cada una de ellas igualamos ngSwitchCase con cada uno de los
valores, para finalmente y también en cada li incorporar una clase css que se
activará en función del valor de la propiedad equipo.
Nos queda añadir las clases CSS, para lo cual incorporamos al archivo
ejdirectivangswitch.component.css el siguiente código CSS:
src/app/ejdirectivangswitch/ejdirectivangswitch.component.css
ul {
text-align: center;
list-style: none;
}
.lakers {
max-width: 600px;
height: 120px;
background-image: url("../../assets/LALakers.png");
background-position-x: 10px;
background-position-y: 10px;
background-repeat: no-repeat;
border-style: solid;
border-width: 5px;
border-color: #552582;
margin-top: 30px;
box-shadow: 0 4px 8px 0 rgba(0, 0, 0, 0.2), 0 6px 20px 0 rgba(0, 0, 0, 0.19);
.celtics {
max-width: 600px;
height: 120px;
background-image: url("../../assets/BostonCeltics.png");
background-position-x: 10px;
background-position-y: 10px;
Página 83
background-repeat: no-repeat;
border-style: solid;
border-width: 5px;
border-color: #008348;
margin-top: 30px;
box-shadow: 0 4px 8px 0 rgba(0, 0, 0, 0.2), 0 6px 20px 0 rgba(0, 0, 0, 0.19);
}
.bulls {
max-width: 600px;
height: 120px;
background-image: url("../../assets/ChicagoBulls.png");
background-position-x: 10px;
background-position-y: 10px;
background-repeat: no-repeat;
border-style: solid;
border-width: 5px;
border-color: #CE1141;
margin-top: 30px;
box-shadow: 0 4px 8px 0 rgba(0, 0, 0, 0.2), 0 6px 20px 0 rgba(0, 0, 0, 0.19);
}
.equipo {
color: #707070;
}
Como hemos añadido unas imágenes de logo a las clases CSS, las tenemos que
ubicar en el directorio assets:
Puedes copiar las imágenes de los archivos de este apartado o bien crear el
ejemplo con tus equipos y deporte favorito.
Página 84
Ahora nos vamos al navegador y comprobamos como cada jugador tiene los
colores de su equipo y que ngSwitch establece la clase CSS en función de valor
de la propiedad equipo de cada objeto.
Página 85
5.6 Creación de directivas propias
src/app/ejdirectivangswitch/ejdirectivangswitch.component.ts
@Directive({
selector: '[appMenuitem]' ②
})
export class MenuitemDirective { ③
constructor() { }
}
Página 86
En nuestro ejemplo, vamos a usar los decoradores HostListener, HostBinding
con lo cual en primer lugar sustituimos la importación por la siguiente:
src/app/ejdirectivangswitch/ejdirectivangswitch.component.ts
@HostListener('mouseover') onOver() { ②
this.mostrar = true;
}
@HostListener('mouseout') onOut() { ③
this.mostrar = false;
}
En el cual :
En resumen, estamos realizando una directiva que permitirá aplicar una clase
CSS cuando se aproxime el ratón al elemento HTML donde se implemente.
Nuestra nueva directiva estará lista para usar, ya que además de crearla, Angular
CLI modifica el archivo app.module.ts para que esté disponible en toda la
aplicación.
Página 87
Lo comprobamos accediendo al archivo:
src/app/app.module.ts
…
import { MenuitemDirective } from './menuitem.directive';
…
MenuitemDirective
]
…
src/app/styles.css
.item-orange {
border-left-style: solid;
border-width: 5px;
border-left-color: orange;
padding-left: 10px;
}
Página 88
src/app/ejmidirectiva/ejmidirectiva.component.html
<div class="container">
<h1 appMenuitem>Título</h1>
<h1 appMenuitem>Descripción</h1>
<h1 appMenuitem>Precio</h1>
</div>
src/app/app.component.html
Página 89
5.7 Utilización de @Input entre componentes
Vamos a ver con un ejemplo como se incorpora este decorador. En primer lugar
creamos un componente padre desde la consola en el directorio raíz del
proyecto con:
src/app/padre/padre.component.html
<h2>Componente Padre</h2>
<div style=" border-style: solid; border-width: 2px; border-color: orange;
padding: 10px">
</div>
src/app/app.component.html
Página 90
Comprobamos en el navegador su correcto funcionamiento:
src/app/hijo/hijo.component.ts
src/app/hijo/hijo.component.html
<h4>{{aviso}}</h4>
src/app/padre/padre.component.html
<h2>Componente Padre</h2>
<div style=" border-style: solid; border-width: 2px; border-color: orange;
padding: 10px">
<app-hijo></app-hijo>
</div>
Página 91
Comprobamos finalmente en el navegador:
Hasta ahora hemos empleado las técnicas de Angular sin mayor novedad, pero
podemos incluir valores en las propiedades del hijo a través del padre, es decir
compartir las propiedades entre dos componentes.
src/app/hijo/hijo.component.ts
@Component({
selector: 'app-hijo',
templateUrl: './hijo.component.html',
styleUrls: ['./hijo.component.css']
})
export class HijoComponent implements OnInit {
constructor() { }
ngOnInit() {
}
Página 92
En el cual:
src/app/padre/padre.component.ts
Y podemos usar la propiedad del hijo para usarla en su plantilla con un valor
proveniente del padre. Para ello en el archivo padre.component.html
modificamos la etiqueta del hijo para añadir esta sintaxis:
src/app/padre/padre.component.html
<app-hijo [aviso]="valorPadre"></app-hijo>
Página 93
Incluso podemos hacerlo más complejo introduciendo un array de valores desde
el padre a la plantilla del hijo. Por ejemplo, en el archivo del componente
padre.component.ts, cambiamos la propiedad por este array:
src/app/padre/padre.component.ts
src/app/padre/padre.component.html
Página 94
5.8 Utilización de @Output entre componentes
src/app/hijo/hijo.component.html
En el cual:
① Añadimos al aviso una directiva ngClass para que aplique la clase tachado si
el valor de leído es true.
Página 95
A continuación vamos a crear la propiedad leido y el método marcar en el
archivo hijo.component.ts:
src/app/hijo/hijo.component.ts
…
@Input() aviso: string;
marcar(event) {
this.leido = !this.leido;
}
…
src/app/hijo/hijo.component.css
.tachado {
text-decoration:line-through;
}
Página 96
Pues bien, la funcionalidad Output permite desencadenar un método del
componente padre a partir de un método del componente hijo y pasar datos
como parámetros.
src/app/hijo/hijo.component.ts
…
import { Component, OnInit, Input, Output, EventEmitter } from
'@angular/core';
…
…
@Output() mensajeMarcado = new EventEmitter();
…
…
detectar(event) {
this.mensaje = this.aviso;
this.mensajeMarcado.emit(this.mensaje);
}
…
Que detectará qué aviso se ha marcado y los emite como parámetro mensaje
del método mensajeMarcado.
Página 97
A continuación en la template del componente hijo, hijo.component.html,
añadimos al botón de marcado de aviso y el método detectar, sustituyendo el
código del botón por el siguiente:
src/app/hijo/hijo.component.html
…
<button *ngIf="leido == false" class="btn btn-success pull-right"
(click)="marcar() ; detectar($event)">Marcar como Leído</button>
…
src/app/padre/padre.component.html
…
<app-hijo *ngFor="let avisop of avisos" [aviso]="avisop"
(mensajeMarcado)="mostrarMensaje($event)"></app-hijo>
…
…
<h3 style="text-align:center"> {{ texto }}</h3>
</div>
Página 98
Por último nos queda modificar el componente padre en el archivo
padre.component.ts. En primer lugar creamos la propiedad texto que se
mostrará en el mensaje añadiendo:
src/app/padre/padre.component.html
…
texto: string;
…
mostrarMensaje(event) {
this.texto = event + ' marcado como leido';
}
Página 99
Anexo Extra I Instalación de Node y NPM
https://nodejs.org/es/
Una vez descargado el archivo .msi lo ejecutamos con doble clic desde nuestra
carpeta de descargas para iniciar el asistente:
Realizamos los pasos que nos vaya solicitando el asistente por defecto, y si nos
fijamos, el asistente instalará tanto Node Js como NPM, y añadirá sus rutas al
path de windows:
Una vez concluida la instalación es necesario reiniciar el equipo para que las
rutas se carguen y podamos emplear node o nmp desde la consola.
node –v
npm –v
En el cual se nos especifica donde han sido instalados Node JS y NPM y como
debemos tener establecido en el path la ruta /usr/local/bin/
Anexo Extra II de Visual Studio Code
Nuestro editor favorito es Visual Studio Code, que además distribuye libremente
Microsoft.
https://code.visualstudio.com/
Para instalar un plugin, pulsamos en el último botón del menú lateral izquierdo
y en el buscador, completamos el nombre de un plugin, por ejemplo HTML
Snippets y pulsamos en el botón verde Instalar:
Para que funcione, en la pantalla de detalle del plugin pulsamos en el botón azul
Recargar y en el cuadro de diálogo pulsamos en Volver a cargar Windows.