---
title: Taller Angular
description: Interacción entre componentes
---
## Conceptos Angular
### Arquitectura
El esquema de la arquitectura del Angular son los [módulos](https://angular.io/guide/architecture-modules), [componentes](https://angular.io/guide/architecture-components#component-metadata), [plantillas](https://angular.io/guide/architecture-components#templates-and-views), [metadatos](https://angular.io/guide/architecture-components#component-metadata), [mapeo de datos](https://angular.io/guide/architecture-components#data-binding), [directivas](https://angular.io/guide/architecture-components#directives), [servicios](https://angular.io/guide/architecture-services) y la [inyección de dependencia](https://angular.io/guide/architecture-services).
* Esquema de la arquitectura

Figura: Esquema de la arquitectura del Angular
---
#### Esquema de la arquitectura

---
### Modulos
En Angular se aplica el enfoque modular en la contrucción de la aplicación Web. Angular cuenta con su propio sistema de modulos llamado `@NgModule`.
Ejemplo :
```javascript=
// Importación de clase a utilizar
import { CommonModule } from "@angular/common";
import { NgModule } from "@angular/core";
import { FormsModule, ReactiveFormsModule } from "@angular/forms";
import { NgbModule } from "@ng-bootstrap/ng-bootstrap";
import { MessageService, ConfirmationService } from "primeng/api";
import { CustomFilterComponent } from "./custom-filter/custom-filter.component";
import { CustomModalComponent } from "./custom-modal/custom-modal.component";
import { CustomToastComponent } from "./custom-toast/custom-toast.component";
import { CustomSpinnerLoaderComponent } from "./loading/custom-spinner-loader.component";
//Decorador de Angular
@NgModule(
//Metadatos asociados al módulo
{
declarations: [
CustomSpinnerLoaderComponent,
CustomToastComponent,
CustomModalComponent,
CustomFilterComponent,
],
imports: [
NgbModule,
CommonModule,
FormsModule,
ReactiveFormsModule,
],
exports: [
CustomSpinnerLoaderComponent,
CustomToastComponent,
CustomModalComponent,
CommonModule,
],
providers: [
MessageService, ConfirmationService
]
}
)
export class CustomCommonModule { }
```
El decorador `@NgModule()` define una función que permite especificar **metadatos**, estos agregan comportamientos adicionales para el módulo. Los metadastos más utilizados son :
* **declarations**: Listado de componentes, directivas y pipes que son parte del módulo.
* **exports**: Listado de componentes, directivas y pipes que serán visible para su utilización en otros componentes, plantillas o módulos.
* **imports**: Listado de módulos que son requeridos para el módulo.
> En cada módulo se define un listado de componentes que pueden ser
> utilizados por otros módulos.
---
### Servicios
Son conjuntos de código y lógica que se ejecutan en forma asíncrona y provee datos a los componentes.
Ejemplo :
```javascript=
// Importación de clase a utilizar
import { HttpClient } from '@angular/common/http';
import { Injectable } from '@angular/core';
import { GlobalService } from '../global-service/global.service';
import { Poblacion } from '../model/poblaciones';
import { ServiceResponse } from '../model/response';
import { ServicioPersonalizadoBase } from '../util/servicio-base-personalizado';
import { MENU_URLS } from 'src/app/util/routes';
//Decorador de Angular
@Injectable(
//Metadatos asociados al servicio
{
providedIn: 'root'
}
)
export class PoblacionesService extends ServicioPersonalizadoBase<ServiceResponse<Poblacion>>{
poblacionInstance: Poblacion | null = null;
constructor(
private http: HttpClient,
private globalSvc: GlobalService,
) {
super(MENU_URLS.POBLACIONES.SERVICE_URL);
this.httpClient = http;
this.globalServices = globalSvc;
}
}
```
* El decorador `@Injectable` es importado desde el `@angular/core`
* El metadado `providedIn: 'root'`: indica al Angular que el servicio estará disponible en forma global para toda la aplicación
:::info
Por defecto al crear un servicio utilizando el Angular CLI se agrega el metadato `providedIn: 'root'` lo que significa que el servicio se instancia una vez y se comparte a nivel de aplicación.
:::
---
### Componentes
Los componentes son bloques de código que gestionan la interacción de las vistas con las aplicaciones en Angular.
Ejemplo :
```javascript=
// Importación de clase a utilizar
import { AfterViewInit, Component, Inject, OnInit, Optional, ViewChild, Input } from '@angular/core';
import { CustomFilterName } from 'src/app/model/custom-filter-name';
import { FilterParam } from 'src/app/model/filter-params';
import { CustomModalService } from 'src/app/services/custom-modal.service';
import { PoblacionesService } from 'src/app/services/poblaciones.service';
import { TituloService } from 'src/app/services/titulo.service';
import { TablaPersonalizadaAbstract } from 'src/app/util/tabla-personalizada-abstract';
import { DataTablePesonalizadoColumn } from 'src/app/model/data-table-personalizado-column';
import { NgbActiveModal } from '@ng-bootstrap/ng-bootstrap';
import { MODAL_DIALOG_DATA } from 'src/app/model/custom-modal-options';
import { MODAL_OPERATION } from 'src/app/model/modal-data';
import { PrimeTablePersonalizadoComponent } from 'src/app/components/prime-table-personalizado/prime-table-personalizado.component';
import { Output } from '@angular/core';
import { EventEmitter } from '@angular/core';
import { ProgramasService } from '../../services/programas.service';
//Decorador de Angular
@Component(
//Metadatos asociados al componente
{
selector: 'app-poblaciones-list',
templateUrl: './poblaciones-list.component.html',
styles: [
]
}
)
export class PoblacionesListComponent extends TablaPersonalizadaAbstract implements OnInit, AfterViewInit {
@ViewChild(PrimeTablePersonalizadoComponent) referenciaTabla: PrimeTablePersonalizadoComponent | null = null;
@Input() mostrarTitulo: boolean = true;
@Input() requierePrograma: boolean = true;
@Input() poblacion: any;
@Output() selectedItemChange: EventEmitter<any> = new EventEmitter();
fnServiceCallBack: any;
modalOperation = MODAL_OPERATION;
fnListadoCallBack: any;
constructor(
private serviceInstance: PoblacionesService,
private modalServiceInstance: CustomModalService,
private tituloServiceInstance: TituloService,
@Optional() public modalInstance: NgbActiveModal,
@Optional() @Inject(MODAL_DIALOG_DATA) public dialogData: any,
private programasService: ProgramasService,
) {
super();
this.entityService = serviceInstance;
this.modalService = modalServiceInstance;
this.tituloService = tituloServiceInstance;
// function to be executed to get data from service
this.fnServiceCallBack = (params: FilterParam) => {
return this.serviceInstance.obtenerListadoFiltradoEnJson(params);
};
}
// Método del ciclo de vida
ngOnInit(): void {
}
// Método del ciclo de vida
ngAfterViewInit() {
}
// Método utilizado para crear un modal y el contenido a mostrar
// dentro de la misma es un componente
abirFormulario(element?: any) {
}
// Método utilizado para eliminar un registro seleccionado
eliminar(element: any) {
}
// Método utilizado para definir el conjunto de atributos a
// mostar en la grilla
obtenerDefinicionTabla(): Array<DataTablePesonalizadoColumn> {
return [];
}
// Método utilizado para definir el conjunto de filtro
// aplicable a la grilla
obtenerDefinicionFiltro(): Array<CustomFilterName> {
return [];
}
//Método para captura el evento emitido por el componente de prime table personalizado
// el mismo captura el item seleccionado y lo vuelve a pasar al componente padre
capturarOperacionSeleccion(datos: any): void {
this.selectedItemChange.next(datos);
}
}
```
* El decorador `Component` es importado desde el `@angular/core`
* `seletor`: Es el selector CSS (identificador de componente), utilizado por el Angular para crear e insertar una instancia del componente donde es utilizado. Por ejemplo, si el componente es utilizado por otro [Módulo](https://angular.io/guide/architecture-modules) dentro de la plantilla HTML `<app-poblaciones-list></app-poblaciones-list>`, entonces Angular inserta una instancia del componente `PoblacionesListComponent` en la posición del tags.
* `templateUrl`: Es la referencia relativa de un archivo de plantilla en HTML que será utilizada por el componente
* `stylesUrl`: Es la referencia relativa de un archivo de estilos en CSS que será utilizada por el componente
---
### Plantillas
La plantilla es una combinación de HTML con tags de Angular que modifican los elementos HTML antes de ser mostrado en la pantalla.
Ejemplo :
```htmlembedded=
<app-custom-spinner-loader></app-custom-spinner-loader>
<div class="card">
<div class="card-body">
<div class="modal-header" *ngIf="mostrarTitulo">
<h4>{{ titulo }}</h4>
</div>
<app-prime-table-personalizado
[ocultarSelector]="requierePrograma"
tipoSelector="radio"
[fnCallBack]="fnServiceCallBack"
[nombreColumnas]="obtenerDefinicionTabla()"
[nombreFiltros]="obtenerDefinicionFiltro()"
(accionChange)="abirFormulario()"
(filaChange)="capturarOperacion($event)"
(selectedChange)="capturarOperacionSeleccion($event)"
>
</app-prime-table-personalizado>
</div>
</div>
```
* Este ejemplo utiliza tags propios del HTML como :
* [div](https://developer.mozilla.org/en-US/docs/Web/HTML/Element/div)
* Así también incluye tags conocidos por el Angular como :
* `<app-custom-spinner-loader>`
* `[ocultarSelector]`
* `(accionChange)`
* `<app-prime-table-personalizado>`
* `*ngIf`
---
## Componente de listado de Población

El componente de listado consta de dos archivos :
* poblaciones-list.component.ts
* poblaciones-list.component.html
El componente de listado permite las siguientes operaciones :
1. Opción de ***agregar***, ***filtar***, ***exportar en pdf*** y ***excel***
2. Opción de ordenamiento por campos definidos en la grilla
3. Opción de ***editar*** y ***eliminar*** por fila de la grilla
4. Opción de ***páginación***
### Diagrama de Clase

### Relación entre componentes

---
### Secuencia de la agregación

* La interacción comienza cuando el usuario oprime clic en el botón de **Agregar+**
1. El evento invoca al método **llamadaFormulario()**, que emite un evento vía el objeto ***EventEmiter*** *(accionChange)*
2. El método *llamadaFormulario* desencadena un evento, el cual es capturado por el componente `PoblacionesListComponent`.
3. El método ***abrirFormulario***, es gestionado en el componente `PoblacionesListComponent` y permite la generación del formulario utilizando un diálogo.
4. Al cerrar el formulario de Población el mismo emite un evento que es capturado por el componente `PoblacionesListComponent`.
5. El evento de ***closeEdit*** es gestionado por el componente `PoblacionesListComponent`, el cual ejecuta un método definido en el componente de `PrimeTablePersonalizadoComponent` con la finalidad de actualizar los valores de la tabla.
---
### Secuencia de ordenación

* La interacción comienza cuando el usuario oprime clic sobre la columna por el cual desea ordenar.
1. El evento invoca al método de **sort()**, que permite configurar los parámetros de ordenamiento en base a la columna seleccionada.
2. Realiza la llamada interna para la obtención de datos desde el ***servicio***.
> En este punto se utiliza la función definida en el componente de `PoblacionesListComponent` ***(fnCallBack)***
> `
this.fnServiceCallBack = (params: FilterParam) => {
return this.serviceInstance.obtenerListadoFiltradoEnJson(params);
};`
3. Se invoca al método de **obtenerListadoFiltradoJson()** del servicio `PoblacionesService`
4. Se invoca al método get del servicio ***HttpClient***, el cual se encarga de obtener los registros del web services de poblaciones.
5. El backend retorna los datos resultantes al servicio del frontend.
6. El Servicio vía el objeto ***Observable*** retorna los registros resultantes al componente.
7. El componente de `PrimeTablePersonalizado` gestiona la renderización de los datos recibidos.
8. El usuario final visualiza los datos actualizados.
---
### Secuencia de edición

* La interacción comienza cuando el usuario oprime clic en el icono de **Editar** de la fila de la tabla.
1. El evento invoca al método **operacionFila()**, que emite un evento vía el objeto ***EventEmiter*** *(filaChange)*
2. El método *operacionFila* desencadena un evento, el cual es capturado por el componente `PoblacionesListComponent`.
3. El método ***capturarOperacion***, es gestionado en el componente`PoblacionesListComponent` y permite la generación del formulario utilizando un diálogo.
4. Al cerrar el formulario de Población el mismo emite un evento que es capturado por el componente `PoblacionesListComponent`.
5. El evento de ***closeEdit*** es gestionado por el componente `PoblacionesListComponent`, el cual ejecuta un método definido en el componente de `PrimeTablePersonalizadoComponent` con la finalidad de actualizar los valores de la tabla.
---
### Secuencia de eliminación

* La interacción comienza cuando el usuario oprime clic en el icono de **Eliminar** de la fila de la tabla.
1. El evento invoca al método **operacionFila()**, que emite un evento vía el objeto ***EventEmiter*** *(filaChange)*
2. El método *operacionFila* desencadena un evento, el cual es capturado por el componente `PoblacionesListComponent`.
3. El método ***capturarOperacion***, es gestionado en el componente`PoblacionesListComponent` y permite la generación del dialogo de confirmación de la operación de eliminación.
4. Al cerrar el dialogo de confirmación el mismo emite un evento que es capturado por el componente `PoblacionesListComponent`.
5. El evento de ***actualizarComponenteTabla*** es gestionado por el componente `PoblacionesListComponent`, el cual ejecuta un método definido en el componente de `PrimeTablePersonalizadoComponent` con la finalidad de actualizar los valores de la tabla.
---
### Secuencia de paginación

1. El evento invoca al método de **page()**, que permite configurar los parámetros de paginación en base a los datos de la página seleccionada.
2. Realiza la llamada interna para la obtención de datos desde el ***servicio***.
> En este punto se utiliza la función definida en el componente de `PoblacionesListComponent` ***(fnCallBack)***
> `
this.fnServiceCallBack = (params: FilterParam) => {
return this.serviceInstance.obtenerListadoFiltradoEnJson(params);
};`
3. Se invoca al método de **obtenerListadoFiltradoJson()** del servicio `PoblacionesService`
4. Se invoca al método get del servicio ***HttpClient***, el cual se encarga de obtener los registros del web services de poblaciones.
5. El backend retorna los datos resultantes al servicio del frontend.
6. El Servicio vía el objeto ***Observable*** retorna los registros resultantes al componente.
7. El componente de `PrimeTablePersonalizado` gestiona la renderización de los datos recibidos.
8. El usuario final visualiza los datos actualizados.
---
## Componente de formulario de Población

El componente de formulario consta de dos operaciones :
* GUARDAR
* CANCELAR
El componente de formulario consta de input tipo text
```htmlembedded=
<div class="form-group">
<label for="nombre">Nombre <span class="text-danger"> (*)</span></label>
<input id="nombre" type="text" required
oninput="this.value = this.value.toUpperCase()"
formControlName="nombre" placeholder="Nombre" class="form-control"
[class.is-invalid]="
entityForm.controls.nombre.invalid &&
entityForm.controls.nombre.touched
" />
<small class="text-danger" [class.d-none]="
entityForm.controls.nombre.valid ||
entityForm.controls.nombre.pristine">
Nombre es requerido
</small>
</div>
```
y selectores que permiten mostrar datos relacionados :
```htmlembedded=
<div class="form-group">
<label for="coberturaGeografica">Cobertura Geográfica <span class="text-danger"> (*)</span></label>
<ng-select required formControlName="coberturaGeografica" [compareWith]="compareOption">
<ng-option *ngFor="let opt of listCobertura | async" [value]="opt">{{opt.nombre}}</ng-option>
</ng-select>
<small class="text-danger" [class.d-none]="
entityForm.controls.coberturaGeografica.valid ||
entityForm.controls.coberturaGeografica.pristine">
Cobertura Geográfica es requerido</small>
</div>
```
### Diagrama de Clase

---
### Relación entre componentes

---
### Servicios utilizados
#### NgModal
[NgModal](https://ng-bootstrap.github.io/#/components/modal/api#NgbModal) :
> Es el servicio principal para la creación de diálogos de tipo modal, que definen el contenedor para el formulario.
> consta de una propiedad principal : **activeInstances** y varios métodos para la interacción con el mismo, el más utilizado es el **open()**
>
#### Inyección de dependencias
> Un componente puede delegar ciertas tareas a los *servicios*, como la obtención de datos del servidor, la validación de la entrada del usuario o el registro directo en la consola. Al definir estas tareas de procesamiento en una clase de **servicio inyectable**, haces que esas tareas estén disponibles para cualquier componente.
##### Ejemplo de inyección de dependencias por tipo de clase
> Normalmente al crear un servicio se genera una clase con el decorador
```javascript=
@Injectable({
providedIn: 'root'
})
```
> con este decorador el Angular gestiona la creación de la instancia de la clase y la pone a disposición de la aplicación.
> La forma de utilizar la inyección de dependencias es a través del constructor de los componentes.
```javascript=
export class CustomModalService {
constructor(private modalService: NgbModal) {
}
}
```
### Secuencia de creación de formulario

---
### Secuencia de la operación Guardar

---
### Secuencia de la operación Actualizar

---
### Paso de parámetro entre componentes padre/hijo
* Desde un componente padre al hijo
1. Utilizando las propiedades (**@Input**) definidas en el hijo
Ejemplo :
```htmlembedded=
<ng-template ngbNavContent>
<app-identificacion-list [poblacion]="params"></app-identificacion-list>
</ng-template>
```
2. Utilizando el servicio padre
Ejemplo :
`poblacionInstance: Poblacion | null = null;`
> Se define una variable de instancia en el servicio padre donde será gestionado el valor a ser compartido con el hijo
3. Utilizando referencia del componente
Ejemplo :
```javascript=
@ViewChild(PrimeTablePersonalizadoComponent) referenciaTabla: PrimeTablePersonalizadoComponent | null = null;
```
> Usando el decorador **(@ViewChild)** podemos acceder a la instancia del componente y a través de ella acceder a las propiedades definidas en el componente para pasar los valores necesarios
### Paso de parámetro entre componentes hijo/padre
* Desde un componente padre al hijo
1. Utilizando las propiedades (**@Output**) definidas en el hijo
Ejemplo :
```htmlembedded=
<app-prime-table-personalizado
(accionChange)="abirFormulario()"
(filaChange)="capturarOperacion($event)"
</app-prime-table-personalizado>
```
2. Utilizando el servicio padre
Ejemplo :
```javascript=
// Se agrega el item previamente vinculado al programa
if(response.respuesta !== null){
this.programasService.problemaItem = response.respuesta.problemas;
}
```
### Paso de parámetro entre componentes - modal
Para los dialogos el paso de párametro se realiza vía el servicio de invocación
Ejemplo :
```javascript=
abrirFormulario(element?: any) {
this.modalServiceInstance?.openForm(PoblacionesFormComponent, {
//Con estos argumentos es posible
//pasar datos al formulario antes de ser construidos
// vía <Injectores>
element: element, data: {
titulo: MENU_URLS.POBLACIONES.TITLE,
}
}).
result.then((operationResult) => {
//En este punto es recibido los
//parámetros desde el formulario de
//población
// la variable <operationResult>
// contendrá los datos
this.referenciaTabla?.filtrar({});
},
reason => {
this.referenciaTabla?.filtrar({});
}
);
}
```
> En el formulario de **PoblacionFormComponente**, se agrega la dependencia del servicio de *NgbActiveModal* el cual permite la referencia al contenedor (dialogo/modal) activo.
```javascript=
export class PoblacionesFormComponent extends CustomAbstractFormComponent implements OnDestroy, OnInit {
constructor(
public modalInstance: NgbActiveModal,
) {
super();
}
// Devuelve el control al componente que lo
// llamó. LLamando al método de close se
// puede pasar los parámetros requeridos al
// componente que lo llamó
closeEdit(element?: any) {
this.modalInstance.close(element);
}
}
```
## Componente de detalle de Población
### Listado de identificación

El componente de listado consta de la operación :
* AGREGAR
---
## Componente de detalle de Población
### Formulario de identificación

El componente de formulario consta de dos operaciones :
* GUARDAR/ACTUALIZAR
* CANCELAR
El componente de formulario consta de input tipo text y selectores que permiten mostrar datos relacionados
## Referencias
* https://angular.io/guide/architecture-services
* https://www.tektutorialshub.com/angular/injection-token-in-angular/