---
# System prepended metadata

title: Taller Angular

---

---
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

![Arquitecuta](https://angular.io/generated/images/guide/architecture/overview2.png)
Figura: Esquema de la arquitectura del Angular

---

#### Esquema de la arquitectura

![](https://i.imgur.com/3JTA06H.png)


---

### 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

![](https://i.imgur.com/GjH45go.png)

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

![](https://i.imgur.com/a5IGCdS.png)

### Relación entre componentes

![](https://i.imgur.com/fUdF2Zx.png)


---

### Secuencia de la agregación

![](https://i.imgur.com/gmp6aVR.png)

* 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 

![](https://i.imgur.com/Wnxh44T.png)

* 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

![](https://i.imgur.com/nNvnNOm.png)

* 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

![](https://i.imgur.com/Fs0wnJf.png)


* 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

![](https://i.imgur.com/nJgm5dA.png)

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

![](https://i.imgur.com/brOuFPR.png)

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

![](https://i.imgur.com/OcyD1e0.png)

---

### Relación entre componentes

![](https://i.imgur.com/TGZfK3U.png)

---

### 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

![](https://i.imgur.com/XgYAgUq.png)

---

### Secuencia de la operación Guardar

![](https://i.imgur.com/3galZoq.png)

---

### Secuencia de la operación Actualizar


![](https://i.imgur.com/zR839j3.png)


---

### 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
![](https://i.imgur.com/Sxr2L9d.png)

El componente de listado consta de la operación : 
* AGREGAR


---

## Componente de detalle de Población
### Formulario de identificación


![](https://i.imgur.com/MRexsW0.png)

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/