Framework: Angular
Contents
Framework: Angular#

Documentación básica de Angular 12
Índice
Configuraciones#
Instalación de Angular CLI#
Para gestionar Angular hay que instalar Angular CLI: npm install -g @angular/cli
Nota
Para instalar en Linux utilizar el comando sudo npm install -g @angular/cli
ANGULAR CLI y otros comandos#
Para ejecutar un comando de Angular CLI el prefijo que se utiliza es ng
:
Comprobar versión de angular/cli:
ng --version
Crear proyecto:
ng new nombre-proyecto
Levantar servidor y abrir navegador:
ng serve -o
(ruta por defecto: localhost:4200)Levantar en otro puerto:
ng serve -o --port 4500
Crear un componente:
ng generate component nombre_componente
Crear componente en linea:
ng generate component comonente_linea -s -t
Crear un pipe:
ng generate pipe nombrePipe
Crear un servicio:
ng generate service nombreServicio
Crear interface en angular:
ng generate interface nombreInterface
Construir aplicación:
ng build
(se guarda en la carpeta dist)Instalar librerías en angular:
ng add @angular/material
Otros comandos útiles de npm#
Instalar todas las dependencias:
npm install
(no es un comando ng pero es importante recordarlo)Instalar servidor para aplicación construida:
npm install -g serve
Ejecutar aplicación angular ya construida (desde su carpeta dentro de dist):
serve
Atención
Para ejecutar en Windows estos comandos CLI se usará la aplicación nodejs command prompt
o ejecutar con el prefijo npm run ng
Estructura del proyecto#
Partes importantes del proyecto:
package.json: archivo con las dependencias del proyecto.
angular.json: se encuentra la configuración del proyecto.
e2e: Carpeta test de integración
src: carpeta del proyecto en la cual vemos:
index.html: pagina de entrada de la aplicación.
main.ts: es donde se cargan los módulos.
style.css: estilos a nivel global.
test.ts: archivo para realizar tests.
enviorments: carpeta para variables de entornos.
assets: carpeta de archivos estáticos como imágenes.
app: carpeta del módulo principal donde se irá añadiendo el resto de componentes.
Componentes#
Los componentes se encuentran en la carpeta src. Es ideal crear una carpeta components dentro de src para ordenarlos ya que se van a reutilizar en distintos módulos. Cada componente se organizará en una carpeta con el siguiente contenido:
Hoja de estilo CSS u otro tipo.
Archivo HTML.
Controlador Typescript.
Modulo Typescript.
Crear un componente#
Para crear un componente se ejecuta el comando: ng generate component nombre_componente
Crear componente dentro de una carpeta components: ng generate component components/menu
Lo primero que vamos a hacer es borrar el contenido del archivo app.component.html y lo reemplazamos por:
1<div>
2 <h1>Componente principal</h1>
3 <hr>
4 <app-menu></app-menu>
5</div>
Ahora editamos el contenido de menu.component.html:
1<div id="menu">
2 <h2>Soy el menú</h2>
3</div>
Y de paso editamos el css de menu en menu.component.css:
1h2{
2 color: red;
3}
Esto mostrará el título del módulo y el subtítulo del componente menú de color rojo.
Atención
Mover la carpeta de un componente de forma manual causará fallos en la aplicación ya que no coincidirán las rutas.
Crear componente en línea#
Un componente en línea contiene en un solo archivo ts, la lógica, el código html y el código css:
Crear componente en linea:
ng generate component comonente_linea -s -t
Data Binding#
Atributos#
Crear y asignar en componente app.component.ts:
1import { Component } from '@angular/core';
2
3@Component({
4 selector: 'app-root',
5 templateUrl: './app.component.html',
6 styleUrls: ['./app.component.css']
7})
8export class AppComponent {
9 // crear una variable en el componente:
10 mensaje: string = "Mensaje desde el componente app";
11}
Utilizar variable en plantilla app.template.html:
1<h1>{{mensaje}}</h1>
Métodos#
Retornar datos de un método:
1import { Component, OnInit } from '@angular/core';
2
3@Component({
4selector: 'app-interpolation',
5templateUrl: './interpolation.component.html',
6styleUrls: ['./interpolation.component.css']
7})
8export class InterpolationComponent implements OnInit {
9// vamos a crear un objeto mixto sin interface:
10consola: any = {
11 marca: 'Sony',
12 modelo: 'PlayStation',
13 lanzamiento: new Date(1995, 9, 29)
14}
15
16constructor() { }
17
18ngOnInit(): void {
19}
20
21// para averiguar la edad creamos un método:
22getEdad(): number {
23 const edad = (new Date().getTime() - this.consola.lanzamiento.getTime()) / (365 * 24 * 60 * 60 * 1000);
24 return Math.ceil(edad);
25}
26
27}
Uso en el template:
1<div class="card">
2 <p>Consola: {{consola.marca}} {{consola.modelo}}</p>
3 <p>Edad: {{getEdad()}} años</p>
4</div>
Assets#
Tratamiento estático de assets en templates:
1<div class="card">
2 <img src="/assets/img/imagen-prueba.jpg">
3</div>
Asignación de assets en componentes:
1imagen: string = '/assets/img/prueba-imagen.jpg';
Atributos dinámicos#
En el controlador existe un atributo con una ruta, se carga la variable en el template:
1<img [src]="imagen">
Nota
Esto vale para cargar información en cualquier atributo de la etiqueta.
Eventos del DOM (event binding)#
Angular dispone de todos los métodos tácticos del DOM usados en HTML para dispara acciones:
En el componente se crea un método:
1import { Component, OnInit } from '@angular/core';
2
3@Component({
4 selector: 'app-saludar',
5 templateUrl: './saludar.component.html',
6 styleUrls: ['./saludar.component.css']
7})
8export class SaludarComponent implements OnInit {
9 // se crea un atributo para el HTML:
10 public saludo: string;
11
12 constructor() {
13 // Se inicializa el atributo con un mensaje o nada:
14 this.saludo = "";
15 }
16
17 ngOnInit(): void {
18 }
19
20 // este método dispara el saludo:
21 startSaludo(): void{
22 this.saludo = "Hola amigo, ¿quién eres?";
23 }
24
25}
Este método ahora se puede disparar al hacer click en el botón:
1<div class="card">
2 <h1>Ejemplo de saludo</h1>
3 <hr>
4 <p>{{ saludo }}</p>
5 <button (click)="startSaludo()">Saludar</button>
6</div>
Recuperar valores de plantilla (Two Way binding)#
Para recuperar valores de la plantilla como datos de un formulario se hace lo siguiente:
Se carga el modulo de formularios en app.module.ts:
1import { NgModule } from '@angular/core';
2import { BrowserModule } from '@angular/platform-browser';
3
4import { AppComponent } from './app.component';
5import { MenuComponent } from './components/menu/menu.component';
6import { InterpolationComponent } from './components/interpolation/interpolation.component';
7import { PropertyBindingComponent } from './components/property-binding/property-binding.component';
8import { EventBindingComponent } from './components/event-binding/event-binding.component';
9import { SaludarComponent } from './components/saludar/saludar.component';
10import { TwowaybindingComponent } from './components/twowaybinding/twowaybinding.component';
11import { FormsModule } from '@angular/forms'; // se importan los forms.
12
13@NgModule({
14declarations: [
15 AppComponent,
16 MenuComponent,
17 InterpolationComponent,
18 PropertyBindingComponent,
19 EventBindingComponent,
20 SaludarComponent,
21 TwowaybindingComponent
22],
23imports: [
24 BrowserModule,
25 FormsModule // se carga en los imports el modulo de forms para todos los componentes de app
26],
27providers: [],
28bootstrap: [AppComponent]
29})
30export class AppModule { }
Ahora pasamos al componente con el que se quiere trabajar:
1import { Component, OnInit } from '@angular/core';
2
3 @Component({
4 selector: 'app-twowaybinding',
5 templateUrl: './twowaybinding.component.html',
6 styleUrls: ['./twowaybinding.component.css']
7 })
8 export class TwowaybindingComponent implements OnInit {
9 // crear objeto donde se va a guardar los datos.
10 consola: any = {
11 marca: null,
12 modelo: null
13 }
14
15 constructor() { }
16
17 ngOnInit(): void {
18 }
19
20}
Y por último se prepara el template:
1<div class="card">
2 <h1>Datos consola</h1>
3 <hr>
4 <p>Consola: {{consola.marca}} {{consola.modelo}}</p>
5 <!-- se le pasa los campos con la directiva ngModel: -->
6 <input type="text" placeholder="marca" [(ngModel)]="consola.marca">
7 <input type="text" placeholder="modelo" [(ngModel)]="consola.modelo">
8</div>
Ciclo de vida#
El ciclo de vida va en el siguiente orden:
Constructor
ngOnChanges
ngOnInit
ngDoCheck
ngAfterContentInit
ngAfterContentChecked
ngAfterViewInit
ngAfterViewChecked
ngOnDestroy
Constructor - Cargar métodos y datos que construyen la aplicación#
La primera acción que se ejecuta en el componente es el constructor y es muy útil para cargar la información antes de disparar cualquier evento como NgOnInit():
1import { Component, OnInit } from '@angular/core';
2
3@Component({
4 selector: 'app-event-binding',
5 templateUrl: './event-binding.component.html',
6 styleUrls: ['./event-binding.component.css']
7})
8export class EventBindingComponent implements OnInit {
9
10 // se crea un elemento, si no se inicializa dará error el linter:
11 public hora: string;
12
13 constructor() {
14 // establecemos la hora con el setHora:
15 this.hora = this.setHora();
16 }
17
18 ngOnInit(): void {
19 }
20
21 // creamos un seteador para la hora:
22 setHora(): string {
23 // recuperamos hora, minutos y segundos actuales:
24 const hh = ('0' + new Date().getHours()).slice(-2);
25 const mm = ('0' + new Date().getHours()).slice(-2);
26 const ss = ('0' + new Date().getHours()).slice(-2);
27 // cargamos el tiempo en hora:
28 return hh + ':' + mm + ':' + ss;
29 }
30
31}
ngOnInit() - Cargar método cuando se inicialice el componente#
1import { Component, OnInit } from '@angular/core';
2
3@Component({
4 selector: 'app-property-binding',
5 templateUrl: './property-binding.component.html',
6 styleUrls: ['./property-binding.component.css']
7})
8export class PropertyBindingComponent implements OnInit {
9
10 imagen: string = '/assets/img/prueba-imagen.jpg';
11
12 constructor() { }
13
14 ngOnInit(): void {
15 // lo cargamos en el DOM al inicializar el componente para que se ejecute:
16 this.cambiarImagen();
17 }
18
19 // crear metodo que cambia imagen:
20 cambiarImagen(): void {
21 const logoRojo = '/assets/img/logo-rojo.jpg';
22 const logoBlanco = '/assets/img/logo-blanco.jpg';
23 setInterval(()=> {
24 this.imagen === logoRojo ? this.imagen = logoBlanco : this.imagen = logoRojo;
25 }, 1000);
26 }
27
28}
ngAfterContentChecked() - Ejecutar después de que se refresque un componente#
Este evento se dispará cuando angular refresca un componente permitiendo ejecutar métodos adicionales en el proceso.
caso de ejemplo con un marcador cuyos jugadores se deben ordenar por los que más han encanastado:
1import { Component, Input, OnInit } from '@angular/core';
2
3@Component({
4 selector: 'app-top-score',
5 templateUrl: './top-score.component.html',
6 styleUrls: ['./top-score.component.css']
7})
8export class TopScoreComponent implements OnInit {
9
10 @Input() equipoLocal: any;
11 @Input() equipoVisitante: any;
12
13 jugadores: any = [];
14
15 constructor() { }
16
17 ngOnInit(): void {
18 this.jugadores = [...this.equipoLocal.jugadores, ...this.equipoVisitante.jugadores];
19 }
20
21 // hook para dispararse cada vez que haya cambios en los valores:
22 ngAfterContentChecked(){
23 this.sortJugadores();
24 }
25
26 sortJugadores() {
27 this.jugadores.sort( (a: any, b: any)=> {
28 return (b.puntos - a.puntos);
29 } );
30 }
31}
Pipes#
El pipe permite formatear valores que vienen del componente.
Pipes de texto#
Tenemos un atributo texto en el componente:
1import { Component, OnInit } from '@angular/core';
2
3@Component({
4 selector: 'app-pipes-angular',
5 templateUrl: './pipes-angular.component.html',
6 styleUrls: ['./pipes-angular.component.css']
7})
8export class PipesAngularComponent implements OnInit {
9 // se crean un atributo con datos:
10 texto: string = 'La mejor consola es la Switch'
11
12 constructor() { }
13
14 ngOnInit(): void {
15 }
16
17}
En el template vamos a ver los pipes:
1<div class="card">
2 <h1>Pipes de texto</h1>
3 <table border=1>
4 <tr>
5 <th>Nombre</th>
6 <th>Valor sin pipe</th>
7 <th>Valor con pipe</th>
8 <th>Descripción</th>
9 </tr>
10 <tr>
11 <td>Uppercase</td>
12 <td>{{ texto }}</td>
13 <td>{{ texto|uppercase }}</td>
14 <td>Todas las letras a mayúsculas</td>
15 </tr>
16 <tr>
17 <td>Lowercase</td>
18 <td>{{ texto }}</td>
19 <td>{{ texto|lowercase }}</td>
20 <td>Todas las letras a minúsculas</td>
21 </tr>
22 <tr>
23 <td>Titlecase</td>
24 <td>{{ texto }}</td>
25 <td>{{ texto|titlecase }}</td>
26 <td>todas las primeras letras a mayúsculas</td>
27 </tr>
28 </table>
29</div>
Pipes de formato y fecha#
Tenemos los siguientes atributos:
1import { Component, OnInit } from '@angular/core';
2
3@Component({
4 selector: 'app-pipes-angular',
5 templateUrl: './pipes-angular.component.html',
6 styleUrls: ['./pipes-angular.component.css']
7})
8export class PipesAngularComponent implements OnInit {
9 // se crea un atributo de tipo mixto:
10 id: any = 11;
11 // también creamos una fecha:
12 fecha: Date = new Date();
13
14 constructor() {
15 // ahora se combina con una nomenclatura:
16 this.id = '000' + this.id;
17 }
18
19 ngOnInit(): void {
20
21 }
22
23}
Y estos son los pypes:
1<div class="card">
2 <h1>Pipes de formato y fecha</h1>
3 <table border=1>
4 <tr>
5 <th>Nombre</th>
6 <th>Valor sin pipe</th>
7 <th>Valor con pipe</th>
8 <th>Descripción</th>
9 </tr>
10 <tr>
11 <td>Slice</td>
12 <td>{{ id }}</td>
13 <td>{{ id|slice: -3 }}</td>
14 <td>Corta un número de caracteres</td>
15 </tr>
16 <tr>
17 <td>Date</td>
18 <td>{{ fecha }}</td>
19 <td>{{ fecha|date: 'dd/MM/yyyy hh:mm' }}</td>
20 <td>Formatea una fecha, también disponible opciones: "long", "medium", "short"</td>
21 </tr>
22 </table>
23</div>
Pipes núméricos#
Estos son los atributos a modificar:
1import { Component, OnInit } from '@angular/core';
2
3@Component({
4 selector: 'app-pipes-angular',
5 templateUrl: './pipes-angular.component.html',
6 styleUrls: ['./pipes-angular.component.css']
7})
8export class PipesAngularComponent implements OnInit {
9 // se crea un atributo numérico:
10 importe: number = 1927.327823;
11
12 constructor() {
13 }
14
15 ngOnInit(): void {
16
17 }
18
19}
Veamos los pipes numéricos:
1<div class="card">
2 <h1>Pipes Numéricos</h1>
3 <table border=1>
4 <tr>
5 <th>Nombre</th>
6 <th>Valor sin pipe</th>
7 <th>Valor con pipe</th>
8 <th>Descripción</th>
9 </tr>
10 <tr>
11 <td>Decimal</td>
12 <td>{{ importe }}</td>
13 <td>{{ importe|number: "5.2-2" }}</td>
14 <td>Establece la cantidad de números mínimos de enteros y los decimales</td>
15 </tr>
16 <tr>
17 <td>Currency</td>
18 <td>{{ importe }}</td>
19 <td>{{ importe|currency: "€" }}</td>
20 <td>Trabaja con divisas, por defecto $ pero se puede cambiar por otro</td>
21 </tr>
22 </table>
23</div>
Crear un pipe#
Para crear un Pipe se utiliza el comando:
ng generate pipe nombrePipe
Generar un pipe en una carpeta:
ng generate pipe pipes/nombrePipe
Editar el pipe:
1import { Pipe, PipeTransform } from '@angular/core';
2
3@Pipe({
4 name: 'nombrePipe'
5})
6
7export class NombrePipePipe implements PipeTransform {
8 // el metodo transform recibe siempre el value y luego podemos definir el tipo de dato que retorna:
9 transform(value: number, decimales: number, moneda?: string): number | string { // se puede poner el parametro opcional ?
10 // vamos a hacer un redondeo:
11 const factor = Math.pow(10,decimales);
12
13 let valorRedondeado;
14 if(value >= 0){
15 valorRedondeado = Math.round(value * factor) / factor;
16 }else{
17 valorRedondeado = Math.round(-value * factor) / factor;
18 }
19 // formatear el valor numérico similar al nuestro:
20 let valorFormateado = new Intl.NumberFormat('de-DE', {minimumFractionDigits: decimales}).format(valorRedondeado);
21
22 return moneda ? valorFormateado + ' ' + moneda : valorFormateado;
23 }
24
25}
Ahora esto se utiliza en un número decimal del template {{ number|nombrePipe:2 }}
o con una moneda {{ number|nombrePipe:2:'€' }}
y lo redondeará a un entero.
Nota
Los args son opcionales, se puede utilizar el método transform solo con el parametro value.
Directivas angular#
Las directivas sirven para controlar el comportamiento de la información desde el template.
Atención
cuando se utilizan números en las cadenas estos se escriben *ngSwitchCase="20"
, si son cadenas *ngSwitchCase="'hola'"
y si son atributos *ngSwitchCase="atributo"
Directivas de control#
Condicional if#
Creamos un atributo edad en el componente:
1import { Component, OnInit } from '@angular/core';
2
3@Component({
4 selector: 'app-directiva-if',
5 templateUrl: './directiva-if.component.html',
6 styleUrls: ['./directiva-if.component.css']
7})
8export class DirectivaIfComponent implements OnInit {
9 // ponemos una edad:
10 public edad: number;
11
12 constructor() {
13 // inicializamos la edad:
14 this.edad = 0;
15 }
16
17 ngOnInit(): void {
18 }
19
20}
En el template veremos el ngIf:
1<div class="row">
2 <h1>ngIf</h1>
3 <input type="number" [(ngModel)]="edad">
4 <p>Tienes {{ edad }} años.</p>
5 <!-- Establecer if: -->
6 <p *ngIf="edad >=18; else menor">Eres mayor de edad</p>
7 <!-- para el else usamos un ng-tempalte: -->
8 <ng-template #menor>
9 <p>Eres menor de edad</p>
10 </ng-template>
11</div>
Atención
Hay que añadir el módulo FormsModule en app.module.ts
Condicional Switch#
Tenemos una edad en el componente igual al ejemplo anterior.
En el template veremos ngSwitch:
1<div class="row">
2 <h1>ngIf</h1>
3 <input type="number" [(ngModel)]="edad">
4 <p>Tienes {{ edad }} años.</p>
5 <!-- Establecer switch: -->
6 <div [ngSwitch]="edad">
7 <p *ngSwitchCase="18">Ya eres mayor de edad!</p>
8 <p *ngSwitchCase="65">Ya eres un anciano!</p>
9 </div>
10</div>
Condicional For#
Creamos una lista de elementos en el componente:
1import { Component, OnInit } from '@angular/core';
2
3@Component({
4 selector: 'app-directiva-for',
5 templateUrl: './directiva-for.component.html',
6 styleUrls: ['./directiva-for.component.css']
7})
8export class DirectivaForComponent implements OnInit {
9 // crear colección:
10 consolas: Array<any>;
11
12 constructor() {
13 // harcodear datos:
14 this.consolas = [
15 {marca: 'Sony', modelo: 'Playstation', lanzamiento: 1995},
16 {marca: 'Sega', modelo: 'Dreamcast', lanzamiento: 1998},
17 {marca: 'Nintendo', modelo: 'Gameboy', lanzamiento: 1989},
18 {marca: 'Nintendo', modelo: 'Gamecube', lanzamiento: 2002},
19 {marca: 'Sony', modelo: 'Playstation 2', lanzamiento: 2001}
20 ]
21 }
22
23 ngOnInit(): void {
24 }
25
26}
Cargar listado en el template:
Nota
Una cosa interesante es que cuando se producen cambios en la información del componente esto se actualizan en la vista automáticamente sin hacer nada.
Directivas de atributos#
Las directivas de atributos al igual que los atributos dinámicos [src], [value], etc… permiten asignar un valor que proviene del componente como el nombre de una clase o el valor de un estilo css.
Implementar clase ngClass#
Tenemos el listado de consolas en el componente:
1import { Component, OnInit } from '@angular/core';
2
3@Component({
4 selector: 'app-clases',
5 templateUrl: './clases.component.html',
6 styleUrls: ['./clases.component.css']
7})
8export class ClasesComponent implements OnInit {
9
10 consolas: Array<any>;
11
12 constructor() {
13 // harcodear datos:
14 this.consolas = [
15 {marca: 'Sony', modelo: 'Playstation', lanzamiento: 1995},
16 {marca: 'Sega', modelo: 'Dreamcast', lanzamiento: 1998},
17 {marca: 'Nintendo', modelo: 'Gameboy', lanzamiento: 1989},
18 {marca: 'Nintendo', modelo: 'Gamecube', lanzamiento: 2002},
19 {marca: 'Sony', modelo: 'Playstation 2', lanzamiento: 2001}
20 ]
21 }
22
23 ngOnInit(): void {
24 }
25
26}
En el css se crean unas clases con los nombres de las marcas:
1.Sony{
2 color: gray;
3}
4
5.Sega{
6 color: blue;
7}
8
9.Nintendo{
10 color: red;
11}
Ahora en el template se implementan las clases según su marca:
1<div class="card">
2
3<table border=1>
4 <tr>
5 <th>ID</th>
6 <th>Consola</th>
7 <th>Marca</th>
8 <th>Lanzamiento</th>
9 </tr>
10 <tr *ngFor="let consola of consolas; let i = index">
11 <!-- ngClass recibe un atributo que compara con el nombre de una clase css -->
12 <td [ngClass]="consola.marca">{{ i + 1 }}</td>
13 <td [ngClass]="consola.marca">{{ consola.modelo }}</td>
14 <td [ngClass]="consola.marca">{{ consola.marca }}</td>
15 <td [ngClass]="consola.marca">{{ consola.lanzamiento }}</td>
16 </tr>
17</table>
18</div>
Implementar estilo ngStyle#
En primer lugar añadimos un atributo edad y un método que defina los colores:
1import { Component, OnInit } from '@angular/core';
2
3@Component({
4 selector: 'app-clases',
5 templateUrl: './clases.component.html',
6 styleUrls: ['./clases.component.css']
7})
8export class ClasesComponent implements OnInit {
9
10 edad: number;
11
12 constructor() {
13 this.edad = 0;
14 }
15
16 ngOnInit(): void {
17 }
18
19 // vamos a crear un método para recuperar el color:
20 getColor(){
21 if(this.edad < 18){
22 return "red";
23 }else if(this.edad >= 18){
24 return "green";
25 }else{
26 return "blue";
27 }
28 }
29
30}
En el template se implementa la directiva:
1<div class="row">
2 <input type="number" [(ngModel)]="edad">
3 <p>Tienes {{ edad }} años.</p>
4 <!-- Establecer switch: -->
5 <p *ngIf="edad >=18; else menor" [ngStyle]="{'color': getColor()}">Eres mayor de edad</p>
6 <!-- para el else usamos un ng-tempalte: -->
7 <ng-template #menor>
8 <p [ngStyle]="{'color': getColor()}">Eres menor de edad</p>
9 </ng-template>
10</div>
Jerarquía de componentes#
Enviar valores de padre a hijo#
El componente padre tiene un valor:
1import { Component, OnInit } from '@angular/core';
2
3@Component({
4 selector: 'app-padre',
5 templateUrl: './padre.component.html',
6 styleUrls: ['./padre.component.css']
7})
8export class PadreComponent implements OnInit {
9 // tenemos un valor en el padre:
10 numeroPadre : number;
11
12 constructor() {
13 // al que se le asigna un número:
14 this.numeroPadre = 30;
15
16 }
17
18 ngOnInit(): void {
19 }
20
21}
El padre envía a través del selector del hijo el atributo numeroPadre:
1<div class="card">
2 <h2>Componente padre</h2>
3 <p>Valor número padre: {{ numeroPadre }}</p>
4 <app-hijo [numeroHijo]="numeroPadre"></app-hijo>
5</div>
El hijo se prepara en el componente para recibir valores del padre:
1// se importa input:
2import { Component, OnInit, Input } from '@angular/core';
3
4@Component({
5 selector: 'app-hijo',
6 templateUrl: './hijo.component.html',
7 styleUrls: ['./hijo.component.css']
8})
9export class HijoComponent implements OnInit {
10 // con el decorador Input se prepara el atributo para recibir los datos:
11 @Input() numeroHijo : number = 0;
12
13 constructor() { }
14
15 ngOnInit(): void {
16 }
17
18}
Ahora se puede utilizar el atributo numeroHijo con los datos del padre:
1<div class="card">
2 <h3>Componente hijo</h3>
3 <p>Valor número hijo: {{ numeroHijo }}</p>
4</div>
Enviar valores de hijo a padre#
El procedimiento es similar, esta vez comenzamos por el componente hijo:
1// se importa output y también el emisor de eventos:
2import { Component, OnInit, Output, EventEmitter } from '@angular/core';
3
4@Component({
5 selector: 'app-hijo',
6 templateUrl: './hijo.component.html',
7 styleUrls: ['./hijo.component.css']
8})
9export class HijoComponent implements OnInit {
10 // con el decorador Output se crea un nuevo objeto de tipo emisor:
11 @Output() valor : EventEmitter<any> = new EventEmitter();
12
13 constructor() { }
14
15 ngOnInit(): void {
16 }
17
18 // preparamos un método para disparar el evento:
19 handleChangeValor(){
20 this.valor.emit({numeroHijo: 50})
21 }
22
23}
Añadimos un botón en el hijo que ejecutará el método emisor:
1<div class="card">
2 <h3>Componente hijo</h3>
3 <button (click)="handleChangeValor()">Cargar valor en el padre</button>
4</div>
El padre deberá tener un método para recibir el evento emitido y actualizar el atributo numérico:
1import { Component, OnInit } from '@angular/core';
2
3@Component({
4 selector: 'app-padre',
5 templateUrl: './padre.component.html',
6 styleUrls: ['./padre.component.css']
7})
8export class PadreComponent implements OnInit {
9 numeroPadre : number;
10
11 constructor() {
12 this.numeroPadre = 0;
13
14 }
15
16 ngOnInit(): void {
17 }
18
19 // recibimos el valor y lo asignamos al numeroPadre:
20 getValor($event: any): void{
21 this.numeroPadre = $event.numeroHijo;
22 }
23
24}
La plantilla solo tendrá que mostrar el número por defecto que cambiará al pulsar el botón:
1<div class="card">
2 <h2>Componente padre</h2>
3 <p>Valor recibido: {{ numeroPadre }}</p>
4 <!-- Ahora se recibe el valor en un método del padre que recibirá el evento: -->
5 <app-hijo (valor)="getValor($event)"></app-hijo>
6</div>
Servicios en Angular#
Crear un servicio:
ng generate service nombreServicio
Crear un servicio en un directorio:
ng generate service services/nombreServicio
:
1import { Injectable } from '@angular/core';
2
3@Injectable({
4 providedIn: 'root' // esto indica que el servicio estará disponible en toda la aplicación
5})
6export class ConsolasService {
7 // se crean los atributos como privados:
8 private consolas: any = [
9 {marca: 'Sony', modelo: 'Playstation', lanzamiento: 1995},
10 {marca: 'Sega', modelo: 'Dreamcast', lanzamiento: 1998},
11 {marca: 'Nintendo', modelo: 'Gameboy', lanzamiento: 1989},
12 {marca: 'Nintendo', modelo: 'Gamecube', lanzamiento: 2002},
13 {marca: 'Sony', modelo: 'Playstation 2', lanzamiento: 2001}
14 ]
15
16 constructor() { }
17
18 // se generan los métodos para obtener el listado:
19 getConsolas(): any {
20 return this.consolas;
21 }
22}
Implementamos el servicio en un componente:
1import { Component, OnInit } from '@angular/core';
2// se importa el servicio:
3import { ConsolasService } from 'src/app/services/consolas.service';
4
5@Component({
6 selector: 'app-directiva-for',
7 templateUrl: './directiva-for.component.html',
8 styleUrls: ['./directiva-for.component.css']
9})
10export class DirectivaForComponent implements OnInit {
11 // crear colección:
12 consolas: Array<any> = [];
13
14 // se instancia por parámetros el servicio:
15 constructor(private consolasService: ConsolasService) {
16
17 }
18
19 ngOnInit(): void {
20 // cuando haya cargado la página y obtenido los clientes se carga en el Init:
21 this.consolas = this.consolasService.getConsolas();
22 }
23
24}
Ya se puede usar el servicio en el template:
1<div class="card">
2 <h1>Listado de consolas con *ngFor</h1>
3
4 <table border=1>
5 <tr>
6 <th>ID</th>
7 <th>Consola</th>
8 <th>Marca</th>
9 <th>Lanzamiento</th>
10 </tr>
11 <tr *ngFor="let consola of consolas; let i = index">
12 <td>{{ i + 1 }}</td>
13 <td>{{ consola.modelo }}</td>
14 <td>{{ consola.marca }}</td>
15 <td>{{ consola.lanzamiento }}</td>
16 </tr>
17 </table>
18</div>
Cargar datos en servicio#
Para enviar información al servicio hacemos lo siguiente:
Ahora se modifica el servicio para añadir un set:
1import { Injectable } from '@angular/core';
2
3@Injectable({
4 providedIn: 'root'
5})
6export class ConsolasService {
7 private consolas: any = [
8 {marca: 'Sony', modelo: 'Playstation', lanzamiento: 1995},
9 {marca: 'Sega', modelo: 'Dreamcast', lanzamiento: 1998},
10 {marca: 'Nintendo', modelo: 'Gameboy', lanzamiento: 1989},
11 {marca: 'Nintendo', modelo: 'Gamecube', lanzamiento: 2002},
12 {marca: 'Sony', modelo: 'Playstation 2', lanzamiento: 2001}
13 ]
14
15 constructor() { }
16
17 getConsolas(): any {
18 return this.consolas;
19 }
20
21 // crear un set que añadirá el nuevo elemento en la lista:
22 setConsola(consola: any): void {
23 this.consolas.push(consola);
24 }
25}
Crear un componente por ejemplo crearConsola y editar su componente:
1import { Component, OnInit } from '@angular/core';
2// se importa el servicio:
3import { ConsolasService } from 'src/app/services/consolas.service';
4
5@Component({
6 selector: 'app-crear-consola',
7 templateUrl: './crear-consola.component.html',
8 styleUrls: ['./crear-consola.component.css']
9})
10export class CrearConsolaComponent implements OnInit {
11 // se prepara el objeto para añadir una consola:
12 consola: any = {
13 marca: '',
14 modelo: '',
15 lanzamiento: ''
16 }
17 // se carga el servicio en el constructor:
18 constructor(private consolasService: ConsolasService) { }
19
20 ngOnInit(): void {
21 }
22
23 // preparamos un método para añadir consola:
24 crearConsola(): void{
25 this.consolasService.setConsola(this.consola);
26 }
27
28}
En su template tendrá un formulario:
1<div class="card">
2 <label>Marca</label>
3 <input type="text" name="marca" [(ngModel)]="consola.marca">
4 <label>Modelo</label>
5 <input type="text" name="modelo" [(ngModel)]="consola.modelo">
6 <label>Lanzamiento</label>
7 <input type="number" name="lanzamiento" [(ngModel)]="consola.lanzamiento">
8 <button (click)="crearConsola()">Añadir</button>
9</div>
Atención
Recuerda que hay que añadir FormsModule en el módulo principal app.
Interfaces Angular#
Crear interface en angular:
ng generate interface nombreInterface
Crear en una carpeta específica:
ng generate interface interfaces/nombreInterface
1export interface Consola {
2 marca: string,
3 modelo: string,
4 lanzamiento: number
5}
Ahora para establecerlo como un tipo de propiedad lo asignamos al atributo:
1import { Component, OnInit } from '@angular/core';
2// se importa la interfaz consolas:
3import { Consolas } from 'src/app/interfaces/consolas';
4import { ConsolasService } from 'src/app/services/consolas.service';
5
6@Component({
7 selector: 'app-crear-consola',
8 templateUrl: './crear-consola.component.html',
9 styleUrls: ['./crear-consola.component.css']
10})
11export class CrearConsolaComponent implements OnInit {
12 // se prepara el objeto para añadir una consola:
13 consola: Consolas = {
14 marca: '',
15 modelo: '',
16 lanzamiento: 0
17 }
18 constructor(private consolasService: ConsolasService) { }
19
20 ngOnInit(): void {
21 }
22
23 crearConsola(): void{
24 this.consolasService.setConsola(this.consola);
25 }
26
27}
Esta interfaz se puede aplicar en donde se necesite ya sea controladores o servicios.
Nota
Si tenemos que definir un listado de objetos podemos declararlo usando el nombre de la intefaz: consolas: Array<NombreInterface> = [];
Rutas en angular#
Si hemos añadido angular routing para crear nuestro proyecto podemos usar las rutas de angular de forma sencilla.
Se crean dos componentes nuevo para páginas:
ng generate component pages/index
yng generate component pages/about
Al iniciar le proyecto se crea un archivo en apps llamado app-routing.module.ts que vamos a editar:
1import { NgModule } from '@angular/core';
2import { RouterModule, Routes } from '@angular/router';
3// importamos los componentes:
4import { AboutComponent } from './pages/about/about.component';
5import { IndexComponent } from './pages/index/index.component';
6
7// Aquí se van añadiendo las rutas:
8const routes: Routes = [
9 {path: '', component: IndexComponent}, // añadimos la ruta raiz
10 {path: 'about', component: AboutComponent} // y las rutas que tengamos según componentes
11];
12
13@NgModule({
14 imports: [RouterModule.forRoot(routes)],
15 exports: [RouterModule]
16})
17export class AppRoutingModule { }
Ahora se añade el enrutador al template de app.component.html:
1<!-- Aquí añadimos la ruta: -->
2<router-outlet></router-outlet>
Enlaces de rutas#
Para crear enlaces en las rutas hacemos lo siguiente en un template como app.component.html:
1<div class="navbar">
2 <h2>Rutas</h2>
3 <!-- Para el enrutamiento se usa routerLink y para indicar que clase css usar cuando esta activo routerLinkActive -->
4 <button routerLink="/" routerLinkActive="seleccionado" [routerLinkActiveOptions]="{exact: true}">Inicio</button><!-- para que la raiz no se quede marcada hay que pasar este tercer parámetro -->
5 <button routerLink="about" routerLinkActive="seleccionado">About</button>
6</div>
7
8<router-outlet></router-outlet>
Nota
Lo ideal es crear un nuevo componente para un navbar
Rutas no existente#
Para solucionar las rutas inexistentes se crea un componente 404: ng generate component pages/error
* Se añade al enrutador:
1import { NgModule } from '@angular/core';
2import { RouterModule, Routes } from '@angular/router';
3import { AboutComponent } from './pages/about/about.component';
4import { ErrorComponent } from './pages/error/error.component';
5// se importa el componente:
6import { IndexComponent } from './pages/index/index.component';
7
8const routes: Routes = [
9 {path: '', component: IndexComponent},
10 {path: 'about', component: AboutComponent},
11 {path: '**', component:ErrorComponent} // va añadido siempre al final esta ruta
12];
13
14@NgModule({
15 imports: [RouterModule.forRoot(routes)],
16 exports: [RouterModule]
17})
18export class AppRoutingModule { }
Ahora quedaría retocar la plantilla de la página para que muestre un error 404 personalizado.
Formularios Reactivos#
Vamos a trabajar con ReactiveFormsModule para implementar validaciones más potentes y otras características.
Lo primero será cargar la librería ReactiveFormsModule en app.module.ts:
1import { NgModule } from '@angular/core';
2import { BrowserModule } from '@angular/platform-browser';
3
4import { AppRoutingModule } from './app-routing.module';
5import { AppComponent } from './app.component';
6import { AboutComponent } from './pages/about/about.component';
7import { IndexComponent } from './pages/index/index.component';
8import { ErrorComponent } from './pages/error/error.component';
9import { CrearConsolaComponent } from './componets/crear-consola/crear-consola.component';
10// se importa la librería ReactiveFormsModule
11import { ReactiveFormsModule } from '@angular/forms';
12
13@NgModule({
14 declarations: [
15 AppComponent,
16 AboutComponent,
17 IndexComponent,
18 ErrorComponent,
19 CrearConsolaComponent
20 ],
21 imports: [
22 BrowserModule,
23 AppRoutingModule,
24 ReactiveFormsModule // y se declara para usar en el modulo app
25 ],
26 providers: [],
27 bootstrap: [AppComponent]
28})
29export class AppModule { }
Ahora se trabaja el componente:
1import { Component, OnInit } from '@angular/core';
2// se importa formgroup, formcontrol y validators:
3import { FormControl, FormGroup, Validators } from '@angular/forms';
4
5@Component({
6 selector: 'app-crear-consola',
7 templateUrl: './crear-consola.component.html',
8 styleUrls: ['./crear-consola.component.css']
9})
10export class CrearConsolaComponent implements OnInit {
11 // creamos el atributo que manejara el form con el tipo FormGroup:
12 public consolaForm: FormGroup;
13
14 constructor() {
15 // se implementa el formulario con sus campos:
16 this.consolaForm = new FormGroup({ // también se aplicarán los validadores:
17 marca: new FormControl('', [Validators.required]),
18 modelo: new FormControl('', [Validators.required]),
19 lanzamiento: new FormControl(0, [Validators.required])
20 });
21 }
22
23 ngOnInit(): void {
24
25 }
26
27 enviarConsola(): void{
28 console.log('se dispara');
29 console.log(this.consolaForm.value);
30 }
31
32}
Ahora pasamos al template a crear el formulario:
1<div class="card">
2<!-- se carga la directiva formgroup con el atributo a una función que guardará la información:-->
3<form [formGroup]="consolaForm" (ngSubmit)="enviarConsola()">
4 <label>Marca</label>
5 <input type="text" formControlName="marca">
6 <div *ngIf="consolaForm.controls['marca'].invalid">El campo es requerido</div>
7 <label>Modelo</label>
8 <input type="text" formControlName="modelo">
9 <div *ngIf="consolaForm.controls['modelo'].invalid">El campo es requerido</div>
10 <label>Lanzamiento</label>
11 <input type="number" formControlName="lanzamiento">
12 <div *ngIf="consolaForm.controls['lanzamiento'].invalid">El campo es requerido</div>
13<!-- Validar todo el formulario antes de poder activar el botón: -->
14<button [disabled]="consolaForm.invalid" type="submit">Enviar</button>
15</form>
16<!-- Para depurar el formulario cargamos con pre los elementos: -->
17<pre>{{ consolaForm.value | json }}</pre>
18</div>
Tipos de validaciones comunes:
pristine: limpio, nada escrito.
dirty: se ha escrito.
touched: ha sido seleccionado.
untouched: no esta seleccionado.
valid: es válido.
invalid: no es válido.
Peticiones HTTP#
Partimos de un proyecto nuevo creado con ng new consolasfront
Preparativos#
Lo primero será cargar el modulo HttpClientsModule en los imports de app.module.ts:
1import { NgModule } from '@angular/core';
2import { BrowserModule } from '@angular/platform-browser';
3
4import { AppComponent } from './app.component';
5import { FormsModule } from '@angular/forms';
6import { DirectivaIfComponent } from './components/directiva-if/directiva-if.component';
7import { DirectivaForComponent } from './components/directiva-for/directiva-for.component';
8import { CrearConsolaComponent } from './components/crear-consola/crear-consola.component'; // se importan los forms.
9// se carga la librería HttpClientModule:
10import { HttpClientModule } from '@angular/common/http';
11
12@NgModule({
13declarations: [
14 AppComponent,
15 DirectivaForComponent,
16 CrearConsolaComponent,
17],
18imports: [
19 BrowserModule,
20 HttpClientModule, // cargamos el httpclientmodule
21 FormsModule
22],
23providers: [],
24bootstrap: [AppComponent]
25})
26export class AppModule { }
Crear servicio Http#
Se crea un nuevo servicio en angular con ng generate service services/consolas
y se edita:
1// se importa la librería http:
2import { HttpClient } from '@angular/common/http';
3import { Injectable } from '@angular/core';
4// importamos map de rxjs:
5import { map } from 'rxjs/operators';
6
7@Injectable({
8providedIn: 'root'
9})
10export class ConsolasService {
11 // definimos la ruta base que será la del servidor API:
12 base: string = 'http://localhost:3500';
13
14 // se carga la librería http en el constructor:
15 constructor(private http: HttpClient) { }
16
17 // utilizamos el getter para hacer la petición get:
18 getConsolas(): any {
19 // esto retorna una petición con get y una respuesta con pipe:
20 return this.http.get(this.base)
21 .pipe( // se mapea la respuesta con rxjs:
22 map((data: any)=> {
23 return data;
24 })
25 );
26 }
27
28 // recuperar un solo valor del mismo modo que antes pero con un endpoint recibido por parametros:
29 getConsola(marca: any): any {
30 return this.http.get(`${this.base}/consola/${marca}`)
31 .pipe(
32 map((data: any)=> {
33 return data;
34 })
35 );
36 }
37
38 // Hacemos un método POST:
39 postConsola(consola: any): any {
40 return this.http.post(`${this.base}/consola/crear/`, consola)
41 .pipe(
42 map((data: any) => {
43 return data;
44 })
45 );
46 }
47
48 // Hacemos un método PUT:
49 putConsola(consola: any, modelo: string): any {
50 return this.http.put(`${this.base}/consola/actualizar/${modelo}`, consola)
51 .pipe(
52 map((data: any) => {
53 return data;
54 })
55 );
56 }
57
58 // hacemos el metodo delete:
59 deleteConsola(modelo: string){
60 return this.http.delete(`${this.base}/consola/eliminar/${modelo}`)
61 .pipe(
62 map((data: any) => {
63 return data;
64 })
65 );
66 }
67}
Creamos un nuevo componente
ng generate components pages/index
para sacar un listado de consolas.Se crea un nuevo componente
ng generate component pages/crearConsola
Se crea un componente
ng generate component pages/actualizar
Añadimos las rutas de los nuevos componentes:
1import { NgModule } from '@angular/core';
2import { RouterModule, Routes } from '@angular/router';
3import { ActualizarComponent } from './pages/actualizar/actualizar.component';
4import { CrearConsolaComponent } from './pages/crear-consola/crear-consola.component';
5import { IndexComponent } from './pages/index/index.component';
6
7const routes: Routes = [
8{path: '', component: IndexComponent},
9{path: 'crear', component: CrearConsolaComponent},
10{path: 'actualizar/:modelo', component: ActualizarComponent}
11];
12
13@NgModule({
14imports: [RouterModule.forRoot(routes)],
15exports: [RouterModule]
16})
17export class AppRoutingModule { }
Peticiones GET#
Se edita el componente:
1import { Component, OnInit } from '@angular/core';
2import { Consolas } from 'src/app/interfaces/consolas';
3import { ConsolasService } from 'src/app/services/consolas.service';
4
5@Component({
6 selector: 'app-index',
7 templateUrl: './index.component.html',
8 styleUrls: ['./index.component.css']
9})
10export class IndexComponent implements OnInit {
11
12 // se crea una colección de objetos de tipo consolas:
13 consolas: Array<Consolas> = [];
14 // se carga el servicio en el constructor:
15 constructor(private consolasService: ConsolasService) {
16
17 }
18
19 ngOnInit(): void {
20 // hay que subscribir los datos a la hora de obtenerlos con rxjs:
21 this.consolasService.getConsolas() // o se usa any o se valida que es de tipo colección de consolas:
22 .subscribe((res:Array<Consolas>)=>{
23 this.consolas = res;
24 }, (err: any) =>{ // si falla se ejecuta esta linea
25 console.log(err);
26 });
27 }
28
29}
Se edita el template:
1<h2>Listado de consolas</h2>
2<table border=1>
3<tr>
4 <th>Marca</th>
5 <th>Modelo</th>
6 <th>Lanzamiento</th>
7</tr>
8<tr *ngFor="let consola of consolas">
9 <td>{{ consola.marca }}</td>
10 <td>{{ consola.modelo }}</td>
11 <td>{{ consola.lanzamiento }}</td>
12</tr>
13</table>
Peticiones POST#
se edita el componente:
1import { Component, OnInit } from '@angular/core';
2// cargamos el router para una redirección:
3import { Router } from '@angular/router';
4// se importa la interfaz consolas:
5import { Consolas } from 'src/app/interfaces/consolas';
6import { ConsolasService } from 'src/app/services/consolas.service';
7
8@Component({
9 selector: 'app-crear-consola',
10 templateUrl: './crear-consola.component.html',
11 styleUrls: ['./crear-consola.component.css']
12})
13export class CrearConsolaComponent implements OnInit {
14 // se prepara el objeto para añadir una consola:
15 consola: Consolas = {
16 marca: '',
17 modelo: '',
18 lanzamiento: 0
19 }
20 // se trae el servicio de consolas y el router para uan redirección:
21 constructor(private consolasService: ConsolasService, private route: Router) { }
22
23 ngOnInit(): void {
24 }
25
26 crearConsola(): void{
27 this.consolasService.postConsola(this.consola)
28 .subscribe((res: any) => {
29 console.log(res); // esto se quita en producción
30 // haremos una redirección al listado:
31 this.route.navigate(['/']);
32 }, (err: any) => {
33 console.log(err);
34 });
35 }
36
37}
Y ahora se edita el template:
1<h2>Crear nueva consola</h2>
2
3<div>
4 <label>Marca</label>
5 <input type="text" name="marca" [(ngModel)]="consola.marca">
6 <label>Modelo</label>
7 <input type="text" name="modelo" [(ngModel)]="consola.modelo">
8 <label>Lanzamiento</label>
9 <input type="number" name="lanzamiento" [(ngModel)]="consola.lanzamiento">
10 <button (click)="crearConsola()">Añadir</button>
11</div>
Nota
Se debería crear un comnponente solo para el formulario y reutilizar en la vista editar pero esto es un ejemplo básico.
Peticiones PUT#
En el template del listado se añade el botón con un parámetro para buscar el elemento:
1<h2>Listado de consolas</h2>
2<table border=1>
3<tr>
4 <th>Marca</th>
5 <th>Modelo</th>
6 <th>Lanzamiento</th>
7</tr>
8<tr *ngFor="let consola of consolas">
9 <td>{{ consola.marca }}</td>
10 <td>{{ consola.modelo }}</td>
11 <td>{{ consola.lanzamiento }}</td>
12 <td>
13 <button routerLink="actualizar/{{ consola.modelo }}">editar</button>
14 </td>
15</tr>
16</table>
Se edita el componente actualizar:
1import { Component, OnInit } from '@angular/core';
2import { ActivatedRoute, Router } from '@angular/router';
3// cargar el interface:
4import { Consolas } from 'src/app/interfaces/consolas';
5// importar el servicio:
6import { ConsolasService } from 'src/app/services/consolas.service';
7
8@Component({
9 selector: 'app-actualizar',
10 templateUrl: './actualizar.component.html',
11 styleUrls: ['./actualizar.component.css']
12})
13export class ActualizarComponent implements OnInit {
14 // crear un atributo donde guardar la marca:
15 modelo: string;
16 // se prepara el objeto para añadir una consola:
17 consola: Consolas = {
18 marca: '',
19 modelo: '',
20 lanzamiento: 0
21 }
22
23 // cargar el modulo de ruta activa para coger el parámetro get y el servicio:
24 constructor(private route: ActivatedRoute, private router: Router, private consolasService: ConsolasService) {
25 // asignar el valor de modelo recibido por parámetros:
26 this.modelo = this.route.snapshot.params['modelo'];
27 // nos subscribimos al servicio:
28 this.consolasService.getConsola(this.modelo)
29 .subscribe((res: any) =>{
30 console.log(res);
31 }, (err: any) => {
32 console.log(err);
33 });
34 }
35
36 ngOnInit(): void {
37 }
38
39 editarConsola(): void {
40 this.consolasService.putConsola(this.consola, this.modelo)
41 .subscribe((res: any) =>{
42 console.log(res);
43 // redireccionamos:
44 this.router.navigate(['/']);
45 }, (err: any) => {
46 console.log(err);
47 });
48 }
49
50}
Crear el template:
1<h2>Editar {{modelo}}</h2>
2
3<div>
4 <label>Marca</label>
5 <input type="text" name="marca" [(ngModel)]="consola.marca">
6 <label>Modelo</label>
7 <input type="text" name="modelo" [(ngModel)]="consola.modelo">
8 <label>Lanzamiento</label>
9 <input type="number" name="lanzamiento" [(ngModel)]="consola.lanzamiento">
10 <button (click)="editarConsola()">Actualizar</button>
11</div>
Peticiones DELETE#
Empezamos en el template del listado:
1<h2>Listado de consolas</h2>
2<table border=1>
3<tr>
4 <th>Marca</th>
5 <th>Modelo</th>
6 <th>Lanzamiento</th>
7</tr>
8<tr *ngFor="let consola of consolas">
9 <td>{{ consola.marca }}</td>
10 <td>{{ consola.modelo }}</td>
11 <td>{{ consola.lanzamiento }}</td>
12 <td>
13 <button routerLink="actualizar/{{ consola.modelo }}">editar</button>
14 </td>
15 <td>
16 <!-- añadir el nuevo boton de eliminar -->
17 <button (click)="eliminarConsola(consola.modelo)">Eliminar</button>
18 </td>
19</tr>
20</table>
Creamos el metodo y hacemos la petición delete:
1import { Component, OnInit } from '@angular/core';
2import { Consolas } from 'src/app/interfaces/consolas';
3import { ConsolasService } from 'src/app/services/consolas.service';
4
5@Component({
6 selector: 'app-index',
7 templateUrl: './index.component.html',
8 styleUrls: ['./index.component.css']
9})
10export class IndexComponent implements OnInit {
11
12 consolas: Array<Consolas> = [];
13 constructor(private consolasService: ConsolasService) {
14
15 }
16
17 ngOnInit(): void {
18 this.cargarClientes();
19 }
20
21 eliminarConsola(modelo: string){
22 this.consolasService.deleteConsola(modelo)
23 .subscribe((res:any)=>{
24 // refrescar pantalla:
25 this.cargarClientes();
26 }, (err: any)=>{
27 console.log(err);
28 });
29 }
30
31 // recuperamos la petición del listado y la añadimos a esta función para reutilizar de manera limpia:
32 cargarClientes(){
33 this.consolasService.getConsolas()
34 .subscribe((res:Array<Consolas>)=>{
35 this.consolas = res;
36 }, (err: any) =>{
37 console.log(err);
38 });
39 }
40
41}
Angular Material#
Angular material es una librería de estilos muy útil en ángular.
Preparación#
Instalar angular material:
ng add @angular/material
Crear módulo para separar la lógica de angular material:
ng generate module material
Cargar modulo material.module.ts en app.material.ts:
1import { NgModule } from '@angular/core';
2import { BrowserModule } from '@angular/platform-browser';
3
4import { AppRoutingModule } from './app-routing.module';
5import { AppComponent } from './app.component';
6import { BrowserAnimationsModule } from '@angular/platform-browser/animations';
7// importamos el módulo:
8import { MaterialModule } from './material/material.module';
9
10@NgModule({
11declarations: [
12 AppComponent
13],
14imports: [
15 BrowserModule,
16 AppRoutingModule,
17 BrowserAnimationsModule,
18 MaterialModule
19],
20providers: [],
21bootstrap: [AppComponent]
22})
23export class AppModule { }
Uso de componentes#
Editar modulo material.module.ts para cargar componentes de angular material y exportarlos:
1import { NgModule } from '@angular/core';
2// cargamos el modulo del elemento a usar de angular material:
3import {MatToolbarModule} from '@angular/material/toolbar';
4
5
6@NgModule({
7declarations: [],
8imports: [ // se importa y se exporta:
9 MatToolbarModule
10],
11exports: [
12 MatToolbarModule
13]
14})
15export class MaterialModule { }
En cualquier template se puede cargar el componente añadido, en este caso MatToolbarModule:
1<mat-toolbar color="primary">
2 <span>Taller angular</span>
3</mat-toolbar>
Nota
En la página https://material.angular.io/components/categories se pueden ver los distintos componentes que pueden añadirse.