1. Sección 5 Expandir Angular
Centro público integrado de formación profesional
Nuevo (desglose IES Campanillas)
Angular 16+ Edición 2023 Sección 5
José García Angular 16+ Edición 2023
2. ¿Qué veremos en esta sección?
Una vez sentadas las bases de Angular en la sección anterior, vamos a seguir
expandiéndolas aquí, con los siguientes temas: Crear proyectos de Angular
1. Profundizar un poco más en los módulos
2. FormsModule
3. ngModel
4. @Inputs
5. @outputs
6. Servicios
7. Métodos en servicios
8. Depuraciones
Angular 16+ Edición 2023 Sección 5
José García Angular 16+ Edición 2023
TS – Temas puntuales de la sección
Aunque todo lo que vamos a a tratar es opcional, la
mayor parte de aplicaciones de Angular usan en
cierto punto cada uno de los temas que están en
esta sección.
La idea es comprender bien los conceptos para que
siempre nos suenen y saber siempre, de donde
viene, que cosa.
4. • ¿Qué necesitamos?
Lo primero es descargar nuestro proyecto desde GitHub.
Creamos un directorio de trabajo, entramos dentro y en la terminal ejecutamos:
# clonar https://github.com/jg...74/02...es.git/
Entramos dentro del directorio y abrimos VSC
# code .
En VSC deberíamos de ver algo tal que así ––––>
Nota: La idea es tener nuestro código en GitHub, bien ordenado, documentado y
listo para mostrar a quien tenga interés.
No olvidemos que GitHub y LindIn, son nuestro porfolio.
Angular 16+ Edición 2023 Sección 5
José García Angular 16+ Edición 2023
TS – Continuación del proyecto
5. • ¿Qué necesitamos?
A continuación, construimos nuestro proyecto gracias a los paquetes:
- package.json,
- Package.lock.json
# npm install
Por último, levantamos el servidor:
# ng serve
En resumen, estos son los pasos que hay que realizar para probar cualquier
proyecto Angular que encontremos en GitHub o en cualquier otro repositorio.:
- Clonar
- Reconstruir
- Servir
Angular 16+ Edición 2023 Sección 5
José García Angular 16+ Edición 2023
TS – Continuación del proyecto
6. Módulo DBZ
(Dragon Ball Z)
Angular 16+ Edición 2023 Sección 5
José García Angular 16+ Edición 2023
TS – Nuevo apartado
7. • ¿Qué necesitamos?
Comenzamos creando el módulo ’dbz’ ç
¿Recuerdas como se crea un módulo?
Dentro de la carpeta del proyecto escribimos lo siguiente en la terminal:
# ng g m dbz
Consultar la hoja de Atajos: Comandos para generar componentes...
Angular 16+ Edición 2023 Sección 5
José García Angular 16+ Edición 2023
TS – Continuación del proyecto
8. • ¿Qué observamos?
Tenemos:
- Definición de la clase módulo,
- Decorador de la clase módulo,
- Importaciones de los módulos que necesitamos; NgModule, CommonModule
Nota. En este caso CommonModule, no es necesario.
A continuación creamos los siguientes directorios dentro de ‘dbz’:
- components, vistos en la Sección 4, para guardar los pequeños componentes de ‘dbz’
- interfaces, que son muy parecidas a las de TS
- pages, no es más que un componente, que agrupa componentes (páginas de navegación)
- services, (todavía no sé que son… ya lo veremos)
Angular 16+ Edición 2023 Sección 5
José García Angular 16+ Edición 2023
TS – Continuación del proyecto
9. • ¿Qué observamos?
Dentro de ‘pages’ creamos el archivo ‘main-page.component.ts’.
¿Recuerdas como se crea un componente?
Dentro del archivo comenzamos a escribir a-com… y pulsamos Tab o Enter.
En el código del esqueleto del componente modificamos lo siguiente:
Angular 16+ Edición 2023 Sección 5
José García Angular 16+ Edición 2023
TS – Continuación del proyecto
10. • TAREA
Debemos aplicar los cambios necesarios para usar el componente, ‘main-page’
Pensemos lo que debemos tener en cuenta:
- ¿Hemos declarado y exportado el componente
‘MainPageComponent’ en ‘dbz.module.ts’?
- ¿Hemos importado el módulo
‘DbzModule’ en ‘app.module.ts’
- Por último, y no menos importante,
¿estamos usando el selector
‘app-dbz-main-page’ en ‘app.component.html’?
Digamos que hemos recorrido las dependencias desde dentro hacia fuera.
Angular 16+ Edición 2023 Sección 5
José García Angular 16+ Edición 2023
TS – Continuación del proyecto
11. • TAREA
Visualmente sería algo así (desde dentro hacia fuera):
Angular 16+ Edición 2023 Sección 5
José García Angular 16+ Edición 2023
TS – Continuación del proyecto
app.module.ts
import { … } from ‘./…’;
imports: […]
app.component.html
<…></…>
<hr>
<app-counter></app-counter>
<hr>
<app-heroes-hero></app-heroes-hero>
<hr>
<app-heroes-list></app-heroes-list>
dbz.module.ts
import { … } from ‘./…’;
declarations: […],
exports: […]
main-page-component.ts
selector: ‘…’
templeUrl: ‘./…’
12. • SOLUCIÓN
Visualmente sería algo así (desde dentro hacia fuera):
Angular 16+ Edición 2023 Sección 5
José García Angular 16+ Edición 2023
TS – Continuación del proyecto
app.module.ts
import { … } from ‘./…’;
imports: [DbzModule]
app.component.html
<app-dbz-main-page></app-dbz-main-page>
<hr>
<app-counter></app-counter>
<hr>
<app-heroes-hero></app-heroes-hero>
<hr>
<app-heroes-list></app-heroes-list>
dbz.module.ts
import { … } from ‘./…’;
declarations: [MainPageComponent],
exports: [MainPageComponent]
main-page-component.ts
selector: ‘…’
templeUrl: ‘./…’
13. • ¿Qué observamos?
El componente de DBZ no es un ‘stand-alone-component module’ así que
tenemos que declararlo y exportarlo para que pueda ser usado.
Se importa el módulo del cuál depende el componente DBZ, para poder hacer uso
de él en la aplicación.
Haciendo esto último simplificamos las dependencias de nuestra aplicación, porque
para los sucesivos componentes que declaremos en el módulo, estos ya quedaran
importados y listos para ser usados.
Por favor, pensad en Angular como la evolución que hubo desde la arquitectura
clásica (estilo romano) (dondé los muros soportaban la carga del techo), a la Gótica
(dónde la carga la soportaban los pilares)
En el primero las ventanas eran pequeñas, en el segundo se posibilitó la creación
de esas vidrieras tan grandes y coloridas.
Angular 16+ Edición 2023 Sección 5
José García Angular 16+ Edición 2023
TS – Continuación del proyecto
15. • TAREA Diseñar la pantalla para nuestra aplicación: Dragon Ball Z
¿Serían capaces de crear algo así?
Escribimos el siguiente código en ‘main-page.component.html’:
siguiente diapositiva…
Angular 16+ Edición 2023 Sección 5
José García Angular 16+ Edición 2023
TS – Diseño de la pantalla
16. • SOLUCIÓN
Angular 16+ Edición 2023 Sección 5
José García Angular 16+ Edición 2023
TS – Diseño de la pantalla
18. • ¿Qué necesitamos?
Necesitamos empequeñecer el código anterior, debemos sintetizarlo de tal modo
que la función resultante del componente, podamos reutilizarla en otro lugar.
Ejemplo:
Mandar los datos necesarios a un componente ‘lista’.
Comencemos creando un componente de ‘lista de personajes’.
Recordemos las dos formas que hemos aprendido para crear un componente:
- Desde (CLI): # ng g c <…>
- Manualmente:
creamos el archivo ‘<…>component.ts’ y
dentro del archivo añadimos el código escribiendo ‘a-compone + Tab’
Aprendamos una tercera forma.
Angular 16+ Edición 2023 Sección 5
José García Angular 16+ Edición 2023
TS – Pensemos en componentes pequeños
19. • ¿Qué necesitamos?
1 2 Nombre del componente: ‘list’
3 Default component
4 Confirm
5 Debemos tener algo tal que así:
Angular 16+ Edición 2023 Sección 5
José García Angular 16+ Edición 2023
TS – Pensemos en componentes pequeños
20. • ¿Qué necesitamos?
Pasos:
1.- Añadimos dbz… al nombre del selector, ‘dbz-list’
Esto hace que el componente tenga más sentido en nuestra aplicación.
2.- Comprobamos que el componente ‘ListComponent’ está declarado en
‘dbz.module.ts’ y podemos hacer uso de este en ‘main-page-component.ts’
3.- En ‘main-page-component.ts’ sustituimos el código del listado por:
<dbz-list></dbz-list>
4.- Pegamos el código del listado en ‘list-component.html’
Si todo está correcto, nada debió de cambiar en el navegador, pero…
ahora podemos hacer uso de esa lista de personajes en cualquier otro lugar.
Angular 16+ Edición 2023 Sección 5
José García Angular 16+ Edición 2023
TS – Pensemos en componentes pequeños
21. • TAREA
Crear el componente ‘add-carácter’ para la parte del código del formulario.
Sigue los pasos realizados para el componente lista.
Recuerda añadir dbz… al nombre del selector una vez creado.
Angular 16+ Edición 2023 Sección 5
José García Angular 16+ Edición 2023
TS – Pensemos en componentes pequeños
22. • SOLUCIÓN
1 2
3 4
Angular 16+ Edición 2023 Sección 5
José García Angular 16+ Edición 2023
TS – Pensemos en componentes pequeños
24. • ¿Qué necesitamos?
Un decorador de componentes que permite la comunicación entre padre e hijo.
Permite que un componente padre, ‘main-page.component.ts’ envie información a
sus componentes hijos: ‘list.component.ts’, ‘add-character.component.ts’, etc…
Definimos el decorador @Input() en el componente ‘list.component.ts’ para que
muestre los datos de personajes que le proporcionará ‘main-page.component.ts’
La idea es que la página principal envie los datos que quiera mostrar a los
diferentes componentes que la implementen.
Archivos involucrados:
main-page.component.ts/html =>(datos)=> list.componet.ts/html + interfaz(Character)
Escribimos el siguiente código en los archivos correspondientes:
siguiente diapositiva…
Angular 16+ Edición 2023 Sección 5
José García Angular 16+ Edición 2023
TS – @Input()
25. Angular 16+ Edición 2023 Sección 5
José García Angular 16+ Edición 2023
TS – @Input()
Uso del Decorador @Input() para la comunicación de datos
desde el componente padre, al componente hijo
character.interface.ts
export interface Character {
name: String;
power: number;
}
main-page.component.ts
import { Character } from '../interfaces/character.interface’;
…
export class MainPageComponent {
public characters: Character [] =[{
name: 'Krillin’,
power: 1000
},{
name: 'Goku’,
power: 9500
},{
name: 'Vegeta’,
power: 7500
}];
}
list.component.ts
import { Component, Input } from '@angular/core’;
import { Character } from '../../interfaces/character.interface';
…
export class ListComponent {
@Input() // No olvidar importar el decorador Input
public characterList: Character[] = [{
name: 'Trunks’,
power: 10
}]
}
main-page.component.html
<dbz-list [characterList]="characters"></dbz-list>
list.component.html
…
<li *ngFor="let character of characterList"
class="list-group-item">
<strong>name: </strong> <span>{{character.name}}</span> -
<strong>Power: </strong> <span>{{character.power}}</span>
</li>
…
1
2
3
El tipo
Character está
definido por
esta interfaz
[characterList]="characters” e @Input() hacen posible la comunicación
26. • ¿Qué observamos?
Veamos una representación gráfica de lo que ocurre.
Angular 16+ Edición 2023 Sección 5
José García Angular 16+ Edición 2023
TS – @Input()
main-page.component.html/ts
list.component.html/ts
.html
…
<li *ngFor="let character of characterList"
class="list-group-item">
.ts
import { …, Input } from '@angular/core';
import { Character } from '../../interfaces/character.interface';
…
export class ListComponent {
@Input() // No olvidar importar el decorador Input
public characterList: Character[] = [{
…
.html
<dbz-list [characterList]="characters"></dbz-list>
.ts
import { Character } from '../interfaces/character.interface’;
…
export class MainPageComponent {
public characters: Character [] =[{
…
27. • ¿Qué observamos?
De la misma forma que la interpolación, permiten la comunicación entre los
archivos :
- list.component.ts
- *ngFor="let character of characterList"
- <strong>name: </strong> <span>{{character.name}}</span>
- list.component.html
- public characterList: Character[] = [{ name: 'Trunks’,
El Decorador, permite la comunicación entre los archivos.
- list.component.ts
- @Input()
- public characterList: Character[] = [{
- main-page.component.html
- <dbz-list [characterList]="characters"></dbz-list>
Angular 16+ Edición 2023 Sección 5
José García Angular 16+ Edición 2023
TS – @Input()
29. • ¿Qué necesitamos?
La directiva ‘ngFor()’ nos ayuda a crear esos elementos HTML que se repiten en
tiempo de ejecución, pero…
¿Tiene ‘ngFor()’ algún índice que podemos usar para referenciar dichos
elementos?
Estos son los principales: index, first, last, eve, odd…
Escribimos el siguiente código en los archivos correspondientes:
siguiente diapositiva…
El siguiente Recurso muestra las variantes de diseño de listas en Bootstrap.
Angular 16+ Edición 2023 Sección 5
José García Angular 16+ Edición 2023
TS – Expandiendo *ngFor()
30. • ¿Qué necesitamos?
list.component.html
<li *ngFor="let character of characterList; let i=index; let isFirst = first; let isLast = last;
let isEven = even; let isOdd = odd;
"class="list-group-item">
<span class="text-primary">{{i}}. </span>
<strong>Name: </strong> <span>{{character.name}}</span> -
<strong>Power: </strong> <span>{{character.power}}</span><br />
<span>Es el primero: {{isFirst}}</span><br />
<span>Es par: {{isEven}}</span><br />
<span>Es impar:{{isOdd}}</span><br />
<span>Es el último: {{isLast}}</span>
</li>
Angular 16+ Edición 2023 Sección 5
José García Angular 16+ Edición 2023
TS – Expandiendo *ngFor()
31. ngClass – Clases
basado en
condiciones
Angular 16+ Edición 2023 Sección 5
José García Angular 16+ Edición 2023
TS – Nuevo apartado
32. • ¿Qué necesitamos?
Es normal que en tiempo de ejecución queramos que los objetos se presenten de
un modo u otro, e incluso que los datos del mismo objeto, tengan
representaciones diferentes.
A continuación dos técnicas para cambiar la visualización de los datos:
Escribimos el siguiente código en el archivo ‘list.component.html’:
siguiente diapositiva…
Angular 16+ Edición 2023 Sección 5
José García Angular 16+ Edición 2023
TS – ngClass – Clases (basado en condiciones)
33. • ¿Qué necesitamos?
TÉCNICA 1 Hacemos uso de las clases
<h4>Listado</h4>
<ul class="list-group">
<li *ngFor="let character of characterList;
let i=index; let isFirst = first; let isLast = last; let isEven = even; let isOdd = odd;"
class="list-group-item {{ isFirst?'list-group-item-success’:
isEven?'list-group-item-primary’:
isLast?'list-group-item-dark’:’’ }}">
<span class="text-primary">{{i+1}}. </span>
<strong>Name: </strong> <span>{{character.name}}</span> -
<strong>Power: </strong> <span>{{character.power}}</span>
</li>
</ul>
Angular 16+ Edición 2023 Sección 5
José García Angular 16+ Edición 2023
TS – ngClass – Clases (basado en condiciones)
34. • ¿Qué necesitamos?
TÉCNICA 2 Hacemos uso de la directiva ‘ngClass’
<h4>Listado</h4>
<ul class="list-group">
<li *ngFor="let character of characterList;
let i=index; let isFirst = first; let isLast = last; let isEven = even; let isOdd = odd;"
class="list-group-item"
[ngClass]="{ 'list-group-item-success': isFirst, 'list-group-item-primary': isEven, 'list-group-item-dark': isLast }">
<span class="text-primary">{{i+1}}. </span>
<strong>Name: </strong> <span>{{character.name}}</span> -
<strong>Power: </strong> <span>{{character.power}}</span>
</li>
</ul>
Angular 16+ Edición 2023 Sección 5
José García Angular 16+ Edición 2023
TS – ngClass – Clases (basado en condiciones)
35. • ¿Qué observamos?
Angular nos ayuda a simplificar la lógica de programación.
La estructuración del código clarifica el código.
Es verdad que tenemos que adaptarnos a un nivel de abstracción:
- aprender dónde está cada cosa,
- como son las relaciones entre los diferentes objetos,
- herramientas del lenguaje, etc…
pero todo es para un propósito mayor:
- el código es más escalable,
- la programación en equipo se simplifica,
- hay un mayor control sobre lo que se programa (todo se verifica al momento)
Angular 16+ Edición 2023 Sección 5
José García Angular 16+ Edición 2023
TS – ngClass – Clases (basado en condiciones)
37. • ¿Qué necesitamos?
Comencemos a trabajar con formularios.
Sintaxis (one-way data-binding):
- (click), esperamos el suceso de eventos
Ejemplo: (click)="increaseBy(1)"
- [value], hacemos uso de los atributos
Ejemplo: [value]="character.name"
Consultar la hoja de Atajos: FormsModule de @angular/forms
Angular 16+ Edición 2023 Sección 5
José García Angular 16+ Edición 2023
TS – FormsModule y ngModel
38. • ¿Qué necesitamos?
Sintaxis (two-way data-binding):
- [(ngModel)], con esta directiva conseguimos:
- escuchar el evento de cambio/acción sobre el objeto que se aplica.
- cambiar los valores del código que programa el objeto que mostramos.
Ejemplo: [(ngModel)]="character.name"
Escribimos el siguiente código en los archivos:
- ‘add-cha.component.html/ts’,
- ‘dbz.module.ts’
siguiente diapositiva…
Angular 16+ Edición 2023 Sección 5
José García Angular 16+ Edición 2023
TS – FormsModule y ngModel
39. • ¿Qué necesitamos?
Muy importante, no olvidar importar el módulo para la gestión de formularios.
Angular 16+ Edición 2023 Sección 5
José García Angular 16+ Edición 2023
TS – FormsModule y ngModel
40. • ¿Qué necesitamos?
Muy importante, usar el intellisense para que automáticamente haga el ‘import’
Angular 16+ Edición 2023 Sección 5
José García Angular 16+ Edición 2023
TS – FormsModule y ngModel
41. • ¿Qué observamos?
Error. Dos formas de resolverlo:
- Este error nos indica que hemos olvidado el atributo que los inputs suelen llevar
a la hora de formar parte de un formulario.
- De no querer hacerlo así tendremos que definir el formulario como un
stand-alone.component.
Este se debe a que Angular intenta por todos los medios controlar todos y cada
uno de los objetos con los que tratamos, ya sea bien en el .ts (con el control de
tipos) o bien en el .html (gestionando las referencias de los mismos, así como los
valores que poseen)
- Añadimos el atributo ’name’ a las etiquetas ‘input’
- Ahora sí vemos como el formulario muestra el contenido del atributo ‘character’
El error desaparece.
Angular 16+ Edición 2023 Sección 5
José García Angular 16+ Edición 2023
TS – FormsModule y ngModel
43. • ¿Qué observamos?
La directiva ‘ngModel’ muestra los valores del atributo ‘character’ gracias a los
atributos que hemos añadido en las etiqueta input (one-way binding)
Cuando modificamos los valores estos se modifican automáticamente en el atributo
‘character’ (two-way binding), tal y como se puede comprobar con el método
‘emitCharacter()’ que hemos implementado.
Cuando pulsamos en el botón ‘Agregar’ ya no se produce el refresco propio de los
formularios con ‘submit’
El evento ‘click’ hace que el botón cumpla su función pero no es ese el lugar
correcto para colocarlo, dado que estamos trabajando con un formulario.
Lo correcto es capturar el evento en el propio formulario.
(En el próximo apartado lo modificaremos)
Angular 16+ Edición 2023 Sección 5
José García Angular 16+ Edición 2023
TS – FormsModule y ngModel
45. • ¿Qué necesitamos?
Un decorador de componentes que permite la comunicación entre hijo y padre.
Permite que un componente hijo, ‘add-character.component.ts’ envie información
a su componente padre: ‘main-page.component.ts’
Definimos el decorador @Output() en el componente
‘add-character.component.ts’ para que emita un evento, producto de haber
agregado un nuevo personaje, que enviará a ‘main-page.component.ts’
La idea es que la página principal reciba el nuevo dato que hemos introducido en el
componente.
Archivos involucrados:
add-character.component.ts/html =>(evento+datos)=> main-page.componet.ts/html
Escribimos el siguiente código en los archivos correspondientes:
siguiente diapositiva…
Angular 16+ Edición 2023 Sección 5
José García Angular 16+ Edición 2023
TS – @Output() Emitir eventos al padre
46. • ¿Qué necesitamos?
Comencemos cambiando el evento del botón.
Podríamos poner en el ‘form’ algo tal que así:
<form class="row" (click)="emitCharacter()">
Pero… aprendamos una nueva directiva: ‘ngSubmit’
<form class="row" (ngSubmit)="emitCharacter()">
También, evita que se recargue la página.
Por último, limpiamos el formulario en el método ‘emitCharacter()’
emitCharacter():void {
console.log(this.character);
this.character.name=’’;
this.character.power=0;
}
Angular 16+ Edición 2023 Sección 5
José García Angular 16+ Edición 2023
TS – @Output() Emitir eventos al padre
47. • ¿Qué necesitamos?
Trabajemos ahora con el decorador @Output()
Básicamente se trata de una función que le permitirá al padre atender los eventos
del hijo.
En nuestro ejemplo:
- Si agregamos un personaje (add-character.component.html/ts) [hijo],
- Se actualiza la página principal (main-page.component.html/ts) [padre]
Una vez se actualiza la página principal Angular propagará los cambios
automáticamente para que el ‘list.component.html/ts’ muestre correctamente los
datos.
Consultar la hoja de Atajos: @Output y RxJS (subscripciones)
Angular 16+ Edición 2023 Sección 5
José García Angular 16+ Edición 2023
TS – @Output() Emitir eventos al padre
48. • ¿Qué necesitamos?
Creamos un objeto que va a
- emitir el personaje nuevo que hemos añadido en el componente
‘add-character.component.ts’ [hijo],
- enviándolo al componente
‘main-page.component.ts’ [padre]
Para eso hacemos uso de la clase ‘EventEmitter’, su método ‘.emit’ y del
decorador ‘@Output()’
Escribimos el siguiente código en los archivos:
- ‘add-character.component.html/ts’,
- ‘main-page.component.html/ts’
siguiente diapositiva…
Angular 16+ Edición 2023 Sección 5
José García Angular 16+ Edición 2023
TS – @Output() Emitir eventos al padre
49. • ¿Qué necesitamos?
add-character.component.ts
import { Component, EventEmitter, Output } from '@angular/core’;
…
export class AddCharacterComponent {
@Output()
public onNewCharacter:EventEmitter<Character> = new EventEmitter();
…
emitCharacter():void {
…
this.onNewCharacter.emit(this.character);
Por favor, no olvidéis de hacer uso del intellisense, este añadirá automáticamente
la clase al ‘import’
Angular 16+ Edición 2023 Sección 5
José García Angular 16+ Edición 2023
TS – @Output() Emitir eventos al padre
50. • ¿Qué necesitamos?
Ahora necesitamos recibir dicho personaje en nuestra página principal
Creamos un método que va a
- recibir el personaje nuevo que hemos añadido en el componente
‘add-character.component.ts’ [hijo],
- usandolo en el componente
‘main-page.component.ts’ [padre]
Y… ¿cómo recibo el valor de ‘character’ en el método que uso en el .html?
Para eso hacemos uso de ‘$event’
$event, al igual que en JavaScript, es un evento global, propio de los eventos,
que que forma parte del lenguaje TS y del que siempre podemos disponer, aún sin
haberlo creado. Contiene absolutamente toda la información referente al evento,
quien lo originó, cuando, dónde, circunstancias…
Angular 16+ Edición 2023 Sección 5
José García Angular 16+ Edición 2023
TS – @Output() Emitir eventos al padre
51. • ¿Qué necesitamos?
main-page.component.html
<dbz-add-character (onNewCharacter)="onNewCharacter($event)"></dbz-add-character>
main-page.component.ts
onNewCharacter(character: Character): void {
console.log("MainPage");
console.log("character");
}
Angular 16+ Edición 2023 Sección 5
José García Angular 16+ Edición 2023
TS – @Output() Emitir eventos al padre
52. Angular 16+ Edición 2023 Sección 5
José García Angular 16+ Edición 2023
TS – @Output() Emitir eventos al padre
Uso del Decorador @Output() para la emisión eventos y datos
desde el componente hijo, al componente padre
add-character.component.ts
import { …, EventEmitter, Output } from '@angular/core’;
…
export class AddCharacterComponent {
@Output()
public onNewCharacter:EventEmitter<Character> = new
EventEmitter();
…
emitCharacter():void {
…
this.onNewCharacter.emit(this.character);
…
main-page.component.ts
…
onNewCharacter(character: Character): void {
console.log("MainPage");
console.log("character");
}
add-character.component.html
…
<form class="row" (ngSubmit)="emitCharacter()">
main-page.component.html
…
<dbz-add-character
(onNewCharacter)="onNewCharacter($event)"></dbz-add-
character>
53. • ¿Qué observamos?
Veamos una representación gráfica de lo que ocurre.
Angular 16+ Edición 2023 Sección 5
José García Angular 16+ Edición 2023
TS – @Output() Emitir eventos al padre
main-page.component.html/ts
add-character.component.html/ts
.ts
import { Component, EventEmitter, Output } from '@angular/core’;
…
export class AddCharacterComponent {
@Output()
public onNewCharacter:EventEmitter<Character> = new EventEmitter();
…
emitCharacter():void {
…
this.onNewCharacter.emit(this.character);
…
.html
…
<dbz-add-character
(onNewCharacter)="onNewCharacter($event)"></dbz-add-
character>
.ts
…
onNewCharacter(character: Character): void {
console.log("MainPage");
console.log("character");
}
54. Formas de depurar
la app
Angular 16+ Edición 2023 Sección 5
José García Angular 16+ Edición 2023
TS – Nuevo apartado
55. • ¿Qué necesitamos?
1.- Devtools de Angular
Las herramientas de desarrollo de React y Vue están más logradas pero Angular
tiene un Framework mucho más elaborado.
Es cuestión de tiempo que Angular mejore ese aspecto.
Angular 16+ Edición 2023 Sección 5
José García Angular 16+ Edición 2023
TS – Formas de depurar la app
56. • ¿Qué necesitamos?
2.- debugger; Con esta instrucción paramos la ejecución/interpretación del código
y posicionándonos encima de los objetos podremos ver los valores.
Angular 16+ Edición 2023 Sección 5
José García Angular 16+ Edición 2023
TS – Formas de depurar la app
57. • ¿Qué observamos?
3.- breakpoints En la misma interfaz, podemos establecer puntos de interrupción
para ir paso a paso y ver el estado de los objetos.
Angular 16+ Edición 2023 Sección 5
José García Angular 16+ Edición 2023
TS – Formas de depurar la app
59. • ¿Qué necesitamos?
Tan simple como esto:
onNewCharacter(character: Character): void {
this.characters.push(character);
}
Como se comentó, Angular propagará dicho valor entre los diferentes componentes
que hagan uso del mismo.
Angular 16+ Edición 2023 Sección 5
José García Angular 16+ Edición 2023
TS – Añadir personaje al listado
60. Angular 16+ Edición 2023 Sección 5
José García Angular 16+ Edición 2023
TS – Añadir personaje al listado
Uso del Decorador @Output() para la emisión eventos y datos
desde el componente hijo, al componente padre
add-character.component.ts
import { …, EventEmitter, Output } from '@angular/core’;
…
export class AddCharacterComponent {
@Output()
public onNewCharacter:EventEmitter<Character> = new
EventEmitter();
…
emitCharacter():void {
…
this.onNewCharacter.emit(this.character);
…
main-page.component.ts
…
onNewCharacter(character: Character): void {
this.characters.push(character);
}
add-character.component.html
…
<form class="row" (ngSubmit)="emitCharacter()">
main-page.component.html
…
<dbz-add-character
(onNewCharacter)="onNewCharacter($event)"></dbz-add-
character>
61. • ¿Qué observamos?
Veamos una representación gráfica de lo que ocurre.
Angular 16+ Edición 2023 Sección 5
José García Angular 16+ Edición 2023
TS – Añadir personaje al listado
main-page.component.html/ts
add-character.component.html/ts
.html
(ngSubmit)="emitCharacter()”
.ts
import { Component, EventEmitter, Output } from '@angular/core’;
…
export class AddCharacterComponent {
@Output()
public onNewCharacter:EventEmitter<Character> = new EventEmitter();
…
emitCharacter():void {
…
this.onNewCharacter.emit(this.character);
…
.html
…
<dbz-list [characterList]="characters"
(onDeleteIndex)="onDeleteIndex($event)"></dbz-list>
.ts
…
onNewCharacter(character: Character): void {
this.characters.push(character);
}
62. • ¿Qué necesitamos?
Hemos añadido elementos a la lista.
¿Qué tal si los borramos?
Añadimos el botón de eliminar a cada componente:
El siguiente Recurso muestra el uso del método ‘.splice()’ de arrays.
Eliminar elementos de una lista.
Angular 16+ Edición 2023 Sección 5
José García Angular 16+ Edición 2023
TS – Eliminar personaje del listado
63. • TAREA
Emitir el índice del personaje sobre el cual se ha pulsado el botón eliminar en el
componente, ‘list.component.html/ts’
Recordemos lo que hicimos al emitir el ‘character’ que queríamos insertar:
- capturar el evento, ‘list.component.html’ y
<button
(click)="emitIndex(i)"
- manejarlo con el método ‘emitIndex(i)’, ‘list.component.ts’
@Output()
public onDeleteIndex:EventEmitter<number> = new EventEmitter();
emitIndex(index: number): void {
this.onDeleteIndex.emit(index);
}
Angular 16+ Edición 2023 Sección 5
José García Angular 16+ Edición 2023
TS – Eliminar personaje del listado
65. • TAREA
Ahora que tenemos el índice del elemento que queremos borrar debemos emitirlo a
través de un evento de Emisión, para que:
- el componente ‘main-page.component.ts’ lo capture, y
- a través de un método ‘onDeleteIndex(index)’ borre el personaje.
Angular 16+ Edición 2023 Sección 5
José García Angular 16+ Edición 2023
TS – Eliminar personaje del listado
66. Angular 16+ Edición 2023 Sección 5
José García Angular 16+ Edición 2023
TS – Añadir personaje al listado
Uso del Decorador @Output() para la emisión eventos y datos
desde el componente hijo, al componente padre
list.component.ts
import { …, EventEmitter, Output } from '@angular/core’;
…
@Output()
public onDeleteIndex:EventEmitter<number> = new EventEmitter();
emitIndex(index: number): void {
this.onDeleteIndex.emit(index);
}
…
main-page.component.ts
…
onDeleteIndex(index: number): void {
this.characters.splice(index, 1);
}
list.component.html
…
<button
(click)="emitIndex(i)"
main-page.component.html
…
<dbz-list [characterList]="characters”
(onDeleteIndex)="onDeleteIndex($event)></dbz-list>
67. • SOLUCIÓN (ELIMINAR)
Veamos una representación gráfica de lo que tenemos que hacer al borrar.
Angular 16+ Edición 2023 Sección 5
José García Angular 16+ Edición 2023
TS – Eliminar personaje del listado
main-page.component.html/ts
list.component.html/ts
.html
(ngSubmit)="emitIndex()”
.ts import {… EventEmitter, Output }
@Output()
public onDeleteIndex:EventEmitter<number> = new EventEmitter();
emitIndex(index: number):void {
this.onDeleteCharacter.emit(this.character);
}
.html
<dbz-list [characterList]="characters”
(onDeleteIndex)="onDeleteIndex($event)></dbz-list>
.ts
onDeleteIndex(index: number): void {
this.characters.splice(index, 1);
}
69. • ¿Qué observamos?
Hasta ahora hemos definido nuestros datos de personajes:
en ‘main-page.component.ts’, pero este no es el mejor sitio para hacerlo,
tampoco es correcto que tengamos nuestra lógica para editarlos, ya que puede que
en otro componente (otras páginas, del mismo nivel, ‘hermanos’) necesiten dicha
información, y compartir dicha información a ese nivel, es complicado.
Angular 16+ Edición 2023 Sección 5
José García Angular 16+ Edición 2023
TS – Servicios
Personajes
public
characters:
Character[] =
[{
name: 'Krillin',
power:
75_000
},
{
name:
'Gohan',
power:
1_950_000
},
{
name:
'Piccolo',
power:
1_200_000
},
{
name: 'Goku',
power:
150_000_000
},
{
name:
'Vegeta',
power:
3_000_000
},
{
name: 'Frieza',
power:
120_000_000
},];
70. • ¿Qué necesitamos?
Para garantizar que los datos con los que trabajamos están encapsulados, son de
única instanciación y disponibles a todos los niveles usaremos los servicios
Singleton.
Los servicios Singleton en Angular se maneja mediante Inyección de dependencias
(DI, en inglés)
Y, ¿que es esto de la (DI)?
Pues, un patrón de diseño en el que se garantiza que los constructores de las
clases reciben los objetos ya instanciados, con lo que se garantiza la
composición en vez de la herencia.
El siguiente Recurso muestra el uso de los servicios Singleton.
Es decir, que una clase solo tengan una única instancia.
Angular 16+ Edición 2023 Sección 5
José García Angular 16+ Edición 2023
TS – Servicios
71. • ¿Qué necesitamos? Ejemplo:
Angular 16+ Edición 2023 Sección 5
José García Angular 16+ Edición 2023
TS – Servicios
Sin Inyección de dependencias Con Inyección de dependencias
class Article{
constructor(){
this.user = new User(); // instancia
this.image = new Image(); // instancia
}
}
/* No es correcto que el constructor de la clase Article se
tenga que encargar de instanciar los elementos que la
constituyen: User e Image
Podemos hablar entonces de acoplamiento, si queremos
usar la Image en otros objetos no podríamos hacerlo */
class Article{
constructor(private user : User, private image: Image){}
}
/* Recuerda: esta es la definición corta de clase */
/* La definición tradicional sería esta: */
class Article{
private user : User;
private image : Image
constructor(user : User, image : Image){
this.image = image;
this.user = user;
}
}
new Article(new User(), new Image()); // instancias
Fuente: https://codigofacilito.com/articulos/angular-di
72. • ¿Qué necesitamos?
Angular 16+ Edición 2023 Sección 5
José García Angular 16+ Edición 2023
TS – Servicios
Con Inyección de dependencias
@NgModule({
providers: [User]
})
@Component({})
class Ejemplo{
// En este ejemp. User es el injector token
constructor(private user : User){}
}
73. • ¿Qué necesitamos?
Creamos el servicio:
- CLI, en línea de comando
- Angular schematic, botón derecho en carpeta ‘service’, pulsar: ‘Angular: Generate service’
- A mano, creando los archivos: .html, .ts, etc…
Hagámoslo a mano:
Creamos el archivo: ‘dbz.services’
Escribimos el siguiente código en los archivos correspondientes:
siguiente diapositiva…
Angular 16+ Edición 2023 Sección 5
José García Angular 16+ Edición 2023
TS – Servicios
74. • ¿Qué necesitamos?
dbz.service.ts
Escribimos: a-ser… y vemos como aparecen todos los componentes disponibles.
Elejimos: a-service y automáticamente nos escribe:
import { Injectable } from '@angular/core';
@Injectable({providedIn: 'root’})
export class ServiceNameService {
constructor() { }
}
Angular 16+ Edición 2023 Sección 5
José García Angular 16+ Edición 2023
TS – Servicios
75. • ¿Qué necesitamos?
Como hasta ahora, con cualquier componente, un servicio es una clase.
@Inyectable, le dirá a angular que trate a la clase como un servicio.
Todos los servicios en Angular, desde la versión 6, implementan ‘providedIn: ‘root’
Sin o lo tuviera tendríamos que definirlo en la parte de los ‘providers’ en el archivo
‘app.module.ts’
Con esto, Angular define al servicio con un ‘Singleton’ en todo el proyecto.
Es decir, no importa dónde yo use ese servicio que, siempre que solicite el valor de
la instancia, mediante Inyección de dependencias, obtendré los mismos datos, el
mismo contenido, los mismos valores.
Angular 16+ Edición 2023 Sección 5
José García Angular 16+ Edición 2023
TS – Servicios
76. • ¿Qué necesitamos?
Modificamos el siguiente fichero:
dbz.service.ts
import { Injectable } from '@angular/core';
import { Character } from '../interfaces/character.interface';
@Injectable({
providedIn: 'root'
})
export class DbzService {
public characters: Character[] = [{
name: 'Krillin’,
power: 75_000
}…
Angular 16+ Edición 2023 Sección 5
José García Angular 16+ Edición 2023
TS – Servicios
Sí, nos hemos traído todo el contenido de la clase en:
‘main-page.component.ts’
y lo hemos pegado en la clase del servicio ‘dbz.service.ts’
77. • ¿Qué necesitamos?
Modificamos el siguiente fichero:
main-page.component.ts
import { Component } from '@angular/core';
import { Character } from '../interfaces/character.interface';
import { DbzService } from '../services/dbz.sevice’;
@Component({
selector: 'app-dbz-main-page',
templateUrl: './main-page.component.html'
})
export class MainPageComponent {
constructor(public dbzService: DbzService) { }
}
Angular 16+ Edición 2023 Sección 5
José García Angular 16+ Edición 2023
TS – Servicios
80. • ¿Qué observamos?
Recordemos que seguimos con el problema de borrar los elementos de la lista en
base al índice que ocupan en el array (o índice de cualquier objeto que lo
implemente)
Los id’s deben de ser únicos para cada personaje.
Si la implementación es correcta, los id’s únicos deben ser algo que quede a cargo
de algún paquete de instalación del proyecto, así nos eximimos de la
responsabilidad de tener colisiones a la hora de identificar a los elementos.
El siguiente Recurso es un paquete para Angular que nos ayuda a generar id’s
únicos con cierto formato.
Angular 16+ Edición 2023 Sección 5
José García Angular 16+ Edición 2023
TS – Paquetes externos uuID
81. • ¿Qué observamos?
Para Angular existe un paquete que nos ayuda a crear id únicos: ‘uuid’
Instalémoslo:
# npm i uuid
Usémoslo importándolo en el servicio ‘dbz.service.ts’:
import { } from 'uuid’;
Vemos que se produce un error por dependencias
Resolvámoslo instalando la dependencia que se nos indica en el error:
# npm i --save-dev @types/uuid
Ahora sí podemos usarlo correctamente en la importación:
import { v4 as uuid } from 'uuid’;
v4 as uuid, utiliza el generador ‘v4’ de id’s únicos con el álias ‘uuid’
Angular 16+ Edición 2023 Sección 5
José García Angular 16+ Edición 2023
TS – Paquetes externos uuID
82. • ¿Qué necesitamos?
Agreguemos un id único al objeto ‘Character’.
¿Recordáis dónde está implementado el tipo de dicho objeto ‘Character’?
Sí, en la interfaz ‘character.interface.ts’:
export interface Character {
id?: string;
name: String;
power: number;
}
Ya que no vamos a proceder a refactorizar toda la aplicación, lo dejamos como
opcional para no tener que cambiar todo el código… por ahora
Angular 16+ Edición 2023 Sección 5
José García Angular 16+ Edición 2023
TS – Paquetes externos uuID
83. • ¿Qué necesitamos?
‘dbz.service.ts’
import { v4 as uuid } from 'uuid';
import { Character } from '../interfaces/character.interface';
@Injectable({
providedIn: 'root'
})
export class DbzService {
public characters: Character[] = [{
id: uuid(),
name: 'Krillin’,
…
Angular 16+ Edición 2023 Sección 5
José García Angular 16+ Edición 2023
TS – Paquetes externos uuID
84. • TAREA
En el servicio ‘dbz.service.ts’ implementamos el método ‘onDeleteId(id: string)’
con el siguiente código:
onDeleteId(id: string): void {
this.characters = this.characters.filter(character => character.id != id);
}
Vemos que nuestra aplicación ha dejado de funcionar.
Las tareas son:
1.- Arreglar los errores producto del la implementación del nuevo método.
2.- Hacer que el id sea obligatorio y no opcional.
Angular 16+ Edición 2023 Sección 5
José García Angular 16+ Edición 2023
TS – Paquetes externos uuID
85. • SOLUCIÓN
1.- Arreglar los errores producto del la implementación del nuevo método.
’main-page.component.html’
<dbz-list [characterList]="dbzService.characters"
(onDeleteId)="dbzService.onDeleteId($event)"></dbz-list>
</div>
…
’main-page.component.ts’
Eliminamos el ‘import { Character }…’ El objeto ya no se usa en este componente.
Angular 16+ Edición 2023 Sección 5
José García Angular 16+ Edición 2023
TS – Paquetes externos uuID
86. • SOLUCIÓN
2.- Hacer que el id sea obligatorio y no opcional.
‘dbz.service.ts’
onNewCharacter(character: Character): void {
// const newCharacter: Character = { id: uuid(), ...character } // operador 'spread’
this.characters.push(character);
}
// const newCharacter…
Se usó cuándo no teníamos implementado el ‘id’ en ‘add-character.component.ts’
public character: Character = {
id: uuid(),
name: 'Videl’,
power: 14_000
}
Angular 16+ Edición 2023 Sección 5
José García Angular 16+ Edición 2023
TS – Paquetes externos uuID
87. • SOLUCIÓN
2.- Hacer que el id sea obligatorio y no opcional.
‘list.component.html’
…
<button
(click)="emitId(character.id)"
class="btn btn-danger">X</button>
</li>
Angular 16+ Edición 2023 Sección 5
José García Angular 16+ Edición 2023
TS – Paquetes externos uuID
‘list.component.ts’
export class ListComponent {
@Output()
public onDeleteId:EventEmitter<string> = new
EventEmitter();
emitId(id: string): void {
this.onDeleteId.emit(id);
}
89. • ¿Qué observamos?
Malas prácticas.
Recordemos que al implementar nuestro servicio, toda la lógica de control sobre el
listado de personajes, ‘main-page.component.ts’, migró a la clase de dicho
servicio, ‘dbz.service.ts’
En nuestro ‘main-page.component.ts’ solo quedó el constructor que instancia
dicho servicio mediante Inyección de dependencias.
export class MainPageComponent {
constructor(public dbzService: DbzService) { }
…
Este servicio se construyo como público y las buenas prácticas aconsejan que sea
privado, lo cuál implica que ya no tengo acceso al mismo desde
’main-page.componente.html’ o cualquier otro componente que lo importe.
Angular 16+ Edición 2023 Sección 5
José García Angular 16+ Edición 2023
TS – Paquetes externos uuID
90. • ¿Qué observamos?
Buenas prácticas.
export class MainPageComponent {
constructor(private dbzService: DbzService) { }
…
Para hacer esto posible debemos crear métodos en la clase que sirvan de puente
para comunicarme con el servicio.
Escribimos el siguiente código en los archivos correspondientes:
siguiente diapositiva…
Angular 16+ Edición 2023 Sección 5
José García Angular 16+ Edición 2023
TS – Paquetes externos uuID
94. • TAREA (extra)
En esta aplicación de Dragón Ball Z hemos implementado:
- El mostrar los personajes (Listado),
- La creación de personajes (botón ‘Agregar’), y
- La eliminación de personajes (botón ‘X’)
La tarea consiste en implementar el botón ‘U’ (update), para modificar a un
personaje.
Angular 16+ Edición 2023 Sección 5
José García Angular 16+ Edición 2023
TS – Paquetes externos uuID
96. • ¿Qué necesitamos?
Guardamos nuestro proyecto en GitHub.
1.- ¿Tenemos cuenta en github.com?
- Si la tienes, recuerda el usuario y contraseña de tu cuenta.
- Si no la tienes, crea una cuenta en github.com, recuerda tu usuario y contraseña.
2.- En la terminal (dentro del directorio del proyecto) ’03-expandir-angular-DBZ’):
- # git init
- # git add .
- # git commit –m ‘Fin de la sección 4’
3.- Accedemos a github.com
4.- Creamos el repositorio: ’03-expandir-angular’
Angular 16+ Edición 2023 Sección 4
José García Angular 16+ Edición 2023
TS – Respaldo en Github
97. • ¿Qué necesitamos?
5.- Copiamos las instrucciones para:
‘push an existing repository from the command line’
6.- Volvemos a la terminal y aplicamos las instrucciones anteriores:
- # git remote add origin https://github.com/jgarmay674/03-expandir-angular.git
- # git branch -M main
- # git push -u origin main
Error: remote: Support for password authentication was removed on August 13, 2021. remote:
Please see https://docs.github.com/en/get-started/getting-started-with-git/about-remote-
repositories#cloning-with-https-urls for information on currently recommended modes of
authentication. fatal: Authentication failed for ‘https://github.com/jgarmay674/02-angular-bases.git’
Angular 16+ Edición 2023 Sección 4
José García Angular 16+ Edición 2023
TS – Respaldo en Github
98. • ¿Qué necesitamos?
7.- Creamos un token, Personal Access Token (PAT)
1 2 3
- Genera un nuevo token (classic)
- Indica el uso del token y ‘No expiration’
- Pulsa el botón ‘Generar token’
Angular 16+ Edición 2023 Sección 4
José García Angular 16+ Edición 2023
TS – Respaldo en Github
99. • ¿Qué necesitamos?
8.- Ahora sí podemos ejecutar:
# git push -u origin main
Solicitará la siguiente información:
- Username (de github.com)
- Password (pegamos el token)
Guardar las credenciales:
Creamos el archivo ‘.netrc’ en el raíz. Contenido:
machine https://github.com/jg...74/02...es.git/
login jg…74
password ghp_NL…7c
Angular 16+ Edición 2023 Sección 4
José García Angular 16+ Edición 2023
TS – Respaldo en Github