|
|
|
# Módulo 2 – Componentes en Angular
|
|
|
|
|
|
|
|
En Angular, los **componentes** son la unidad fundamental para construir la interfaz de usuario. Cada componente encapsula una parte de la aplicación, combinando **lógica**, **vista** y **estilos**. Este bloque profundiza en cómo diseñar, reutilizar y comunicar componentes, así como en la integración de librerías externas dentro de la aplicación **Panacea**, orientada a la gestión de recursos sanitarios.
|
|
|
|
|
|
|
|
---
|
|
|
|
|
|
|
|
## Sesión 5 – Primer componente: vista principal
|
|
|
|
|
|
|
|
### Introducción teórica
|
|
|
|
|
|
|
|
Un **componente** representa una sección concreta de la interfaz de usuario. Puede entenderse como un bloque autónomo que controla qué se muestra y cómo se comporta una parte de la aplicación. En Angular, toda aplicación se construye a partir de componentes organizados de forma jerárquica.
|
|
|
|
|
|
|
|
En esta sesión se crea el primer componente funcional de Panacea, que actúa como **vista principal** y punto de entrada visual de la aplicación.
|
|
|
|
|
|
|
|
### Creación con Angular CLI
|
|
|
|
|
|
|
|
```bash
|
|
|
|
ng generate component pages/dashboard
|
|
|
|
```
|
|
|
|
|
|
|
|
### Estructura de un componente
|
|
|
|
|
|
|
|
```ts
|
|
|
|
@Component({
|
|
|
|
selector: 'app-dashboard',
|
|
|
|
templateUrl: './dashboard.component.html',
|
|
|
|
styleUrls: ['./dashboard.component.css']
|
|
|
|
})
|
|
|
|
export class DashboardComponent {
|
|
|
|
titulo = 'Panel de recursos sanitarios';
|
|
|
|
}
|
|
|
|
```
|
|
|
|
|
|
|
|
### Separación de lógica y vista
|
|
|
|
|
|
|
|
La clase del componente contiene la lógica y los datos, mientras que la plantilla HTML se limita a representar esa información.
|
|
|
|
|
|
|
|
```ts
|
|
|
|
export class DashboardComponent {
|
|
|
|
recursos = [
|
|
|
|
{ id: 1, codigo: 'REC-01', tipo: 'Ambulancia', estado: 'Disponible' },
|
|
|
|
{ id: 2, codigo: 'REC-02', tipo: 'Helicóptero', estado: 'En servicio' }
|
|
|
|
];
|
|
|
|
}
|
|
|
|
```
|
|
|
|
|
|
|
|
```html
|
|
|
|
<h1>{{ titulo }}</h1>
|
|
|
|
|
|
|
|
<ul>
|
|
|
|
<li *ngFor="let recurso of recursos">
|
|
|
|
{{ recurso.codigo }} - {{ recurso.tipo }} - {{ recurso.estado }}
|
|
|
|
</li>
|
|
|
|
</ul>
|
|
|
|
```
|
|
|
|
|
|
|
|
### Estilos por componente
|
|
|
|
|
|
|
|
```css
|
|
|
|
h1 {
|
|
|
|
color: #2c3e50;
|
|
|
|
}
|
|
|
|
```
|
|
|
|
|
|
|
|
---
|
|
|
|
|
|
|
|
## Sesión 6 – Componentes reutilizables
|
|
|
|
|
|
|
|
### Introducción teórica
|
|
|
|
|
|
|
|
La **reutilización de componentes** permite construir aplicaciones más mantenibles y escalables. Cuando una parte de la interfaz se repite o tiene una responsabilidad clara, debe convertirse en un componente reutilizable. Esto reduce duplicación, facilita cambios y mejora la legibilidad del código.
|
|
|
|
|
|
|
|
### Componente reutilizable: cabecera
|
|
|
|
|
|
|
|
```bash
|
|
|
|
ng generate component layout/header
|
|
|
|
```
|
|
|
|
|
|
|
|
```ts
|
|
|
|
@Component({
|
|
|
|
selector: 'app-header',
|
|
|
|
templateUrl: './header.component.html',
|
|
|
|
styleUrls: ['./header.component.css']
|
|
|
|
})
|
|
|
|
export class HeaderComponent {
|
|
|
|
appName = 'Panacea';
|
|
|
|
}
|
|
|
|
```
|
|
|
|
|
|
|
|
```html
|
|
|
|
<header>
|
|
|
|
<h2>{{ appName }}</h2>
|
|
|
|
<span>Sistema de gestión de recursos sanitarios</span>
|
|
|
|
</header>
|
|
|
|
```
|
|
|
|
|
|
|
|
### Uso del componente en una vista
|
|
|
|
|
|
|
|
```html
|
|
|
|
<app-header></app-header>
|
|
|
|
<app-dashboard></app-dashboard>
|
|
|
|
```
|
|
|
|
|
|
|
|
### Encapsulación de estilos
|
|
|
|
|
|
|
|
```css
|
|
|
|
header {
|
|
|
|
background-color: #e3f2fd;
|
|
|
|
padding: 1rem;
|
|
|
|
}
|
|
|
|
```
|
|
|
|
|
|
|
|
---
|
|
|
|
|
|
|
|
## Sesión 7 – Comunicación entre componentes (Inputs)
|
|
|
|
|
|
|
|
### Introducción teórica
|
|
|
|
|
|
|
|
Los **parámetros de entrada** permiten enviar datos desde un componente padre a un componente hijo. En Angular, esto se realiza mediante el decorador `@Input()`.
|
|
|
|
|
|
|
|
Conceptualmente, un `@Input()` puede compararse con un **parámetro de un constructor**: define qué información necesita un componente para funcionar correctamente, pero sin controlar cómo se crea.
|
|
|
|
|
|
|
|
### Componente listado de recursos
|
|
|
|
|
|
|
|
```bash
|
|
|
|
ng generate component recursos/resource-list
|
|
|
|
```
|
|
|
|
|
|
|
|
```ts
|
|
|
|
export class ResourceListComponent {
|
|
|
|
@Input() recursos: any[] = [];
|
|
|
|
}
|
|
|
|
```
|
|
|
|
|
|
|
|
### Paso de datos desde el componente padre
|
|
|
|
|
|
|
|
```ts
|
|
|
|
export class DashboardComponent {
|
|
|
|
recursos = [
|
|
|
|
{ id: 1, codigo: 'REC-01', tipo: 'Ambulancia', estado: 'Disponible' },
|
|
|
|
{ id: 2, codigo: 'REC-02', tipo: 'Helicóptero', estado: 'En servicio' }
|
|
|
|
];
|
|
|
|
}
|
|
|
|
```
|
|
|
|
|
|
|
|
```html
|
|
|
|
<app-resource-list [recursos]="recursos"></app-resource-list>
|
|
|
|
```
|
|
|
|
|
|
|
|
```html
|
|
|
|
<ul>
|
|
|
|
<li *ngFor="let recurso of recursos">
|
|
|
|
{{ recurso.codigo }} - {{ recurso.tipo }} - {{ recurso.estado }}
|
|
|
|
</li>
|
|
|
|
</ul>
|
|
|
|
```
|
|
|
|
|
|
|
|
---
|
|
|
|
|
|
|
|
## Sesión 8 – Comunicación entre componentes (Outputs)
|
|
|
|
|
|
|
|
### Introducción teórica
|
|
|
|
|
|
|
|
Los **eventos** permiten que un componente hijo notifique acciones al componente padre. En Angular, esto se gestiona mediante `@Output()` y `EventEmitter`.
|
|
|
|
|
|
|
|
Mientras que los `@Input()` reciben datos, los `@Output()` **emiten eventos**, permitiendo una comunicación clara y desacoplada entre componentes.
|
|
|
|
|
|
|
|
### Componente recurso individual
|
|
|
|
|
|
|
|
```bash
|
|
|
|
ng generate component recursos/resource-item
|
|
|
|
```
|
|
|
|
|
|
|
|
```ts
|
|
|
|
export class ResourceItemComponent {
|
|
|
|
@Input() recurso: any;
|
|
|
|
@Output() seleccionar = new EventEmitter<any>();
|
|
|
|
|
|
|
|
onClick() {
|
|
|
|
this.seleccionar.emit(this.recurso);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
```
|
|
|
|
|
|
|
|
```html
|
|
|
|
<div (click)="onClick()">
|
|
|
|
{{ recurso.codigo }} - {{ recurso.tipo }} - {{ recurso.estado }}
|
|
|
|
</div>
|
|
|
|
```
|
|
|
|
|
|
|
|
### Captura del evento en el padre
|
|
|
|
|
|
|
|
```html
|
|
|
|
<app-resource-item
|
|
|
|
*ngFor="let rec of recursos"
|
|
|
|
[recurso]="rec"
|
|
|
|
(seleccionar)="mostrarDetalle($event)">
|
|
|
|
</app-resource-item>
|
|
|
|
```
|
|
|
|
|
|
|
|
```ts
|
|
|
|
mostrarDetalle(recurso: any) {
|
|
|
|
this.recursoSeleccionado = recurso;
|
|
|
|
this.mostrarModal = true;
|
|
|
|
}
|
|
|
|
```
|
|
|
|
|
|
|
|
---
|
|
|
|
|
|
|
|
## Sesión 9 – Ciclo de vida de los componentes
|
|
|
|
|
|
|
|
### Introducción teórica
|
|
|
|
|
|
|
|
El **ciclo de vida de un componente** describe las distintas fases por las que pasa desde que se crea hasta que se destruye. Angular expone estos momentos mediante métodos llamados **hooks**, que permiten ejecutar lógica en instantes concretos.
|
|
|
|
|
|
|
|
### `ngOnInit`
|
|
|
|
|
|
|
|
Se utiliza para inicializar datos.
|
|
|
|
|
|
|
|
```ts
|
|
|
|
export class DashboardComponent implements OnInit {
|
|
|
|
ngOnInit() {
|
|
|
|
console.log('Vista principal inicializada');
|
|
|
|
}
|
|
|
|
}
|
|
|
|
```
|
|
|
|
|
|
|
|
### `ngOnChanges`
|
|
|
|
|
|
|
|
Se ejecuta cuando cambian los valores recibidos por `@Input()`.
|
|
|
|
|
|
|
|
```ts
|
|
|
|
export class ResourceListComponent implements OnChanges {
|
|
|
|
@Input() recursos: any[] = [];
|
|
|
|
|
|
|
|
ngOnChanges() {
|
|
|
|
console.log('Listado de recursos actualizado');
|
|
|
|
}
|
|
|
|
}
|
|
|
|
```
|
|
|
|
|
|
|
|
### `ngOnDestroy`
|
|
|
|
|
|
|
|
Permite limpiar recursos antes de que el componente desaparezca.
|
|
|
|
|
|
|
|
```ts
|
|
|
|
export class ResourceItemComponent implements OnDestroy {
|
|
|
|
ngOnDestroy() {
|
|
|
|
console.log('Componente de recurso destruido');
|
|
|
|
}
|
|
|
|
}
|
|
|
|
```
|
|
|
|
|
|
|
|
---
|
|
|
|
|
|
|
|
## Sesión 10 – Importación de librerías externas (PrimeNG)
|
|
|
|
|
|
|
|
### Introducción teórica
|
|
|
|
|
|
|
|
Las **librerías externas** amplían las capacidades de Angular ofreciendo componentes, utilidades o estilos ya implementados. Su uso permite acelerar el desarrollo y mantener una interfaz consistente.
|
|
|
|
|
|
|
|
La documentación oficial de cada librería es siempre la principal fuente de referencia y suele encontrarse en su sitio web o repositorio oficial.
|
|
|
|
|
|
|
|
### Instalación de PrimeNG
|
|
|
|
|
|
|
|
```bash
|
|
|
|
npm install primeng primeicons
|
|
|
|
```
|
|
|
|
|
|
|
|
### Importación de un módulo
|
|
|
|
|
|
|
|
```ts
|
|
|
|
import { DialogModule } from 'primeng/dialog';
|
|
|
|
|
|
|
|
@NgModule({
|
|
|
|
imports: [
|
|
|
|
DialogModule
|
|
|
|
]
|
|
|
|
})
|
|
|
|
export class AppModule {}
|
|
|
|
```
|
|
|
|
|
|
|
|
### Uso de un componente PrimeNG (modal)
|
|
|
|
|
|
|
|
```html
|
|
|
|
<p-dialog
|
|
|
|
header="Detalle del recurso"
|
|
|
|
[(visible)]="mostrarModal"
|
|
|
|
[modal]="true">
|
|
|
|
|
|
|
|
<div *ngIf="recursoSeleccionado">
|
|
|
|
<p>Código: {{ recursoSeleccionado.codigo }}</p>
|
|
|
|
<p>Tipo: {{ recursoSeleccionado.tipo }}</p>
|
|
|
|
<p>Estado: {{ recursoSeleccionado.estado }}</p>
|
|
|
|
</div>
|
|
|
|
|
|
|
|
</p-dialog>
|
|
|
|
```
|
|
|
|
|
|
|
|
```ts
|
|
|
|
mostrarModal = false;
|
|
|
|
recursoSeleccionado: any = null;
|
|
|
|
``` |