0.0.1 • Published 5 years ago

demo-hg-angular v0.0.1

Weekly downloads
7
License
-
Repository
-
Last release
5 years ago

HG-ANGULAR (Hunuk Generic Angular)

La motivación proncipal de la librearia es la de crear elementos comunes que se presentan en distintos desarrollos para poder distribuirlos desde este repositorio y centralizar su evolución. Con esta libreria vas a poder crear aplicaciones angular de manera mucho mas ágil, centrado la total atención en el problema a resolver y no al desarrollo de componentes como modales, alertas, tablas, etc.

Getting Started

Antes que nada se debe configurar el prefijo de la ruta en el archivo environments/environment.ts y environments/environment.prod.ts, agregandole el atributo urlApi al json, de la siguiente manera:

export const environment = {
   ...
  urlApi: 'api'
};

suponiendo que todos nuestros request deban dirigirse al contexto /api. Por ultimo se debe configurar ese valor en el import del modulo.

...
import { environment } from 'src/environments/environment';
....

@NgModule({
  ...
  imports: [
    ...
    HGAngularModule.forRoot(
      {urlApi: environment.urlApi}
    ),
    ...
  ],
  ...
})
export class AppModule { }

Luego de tener configurado esto podemos proceguir a crear nuestro primer ABML.

Simple Crud

El simple crud es un componente que muestra una tabla con la información de la entidad junto a un filtro, un boton para agregar, editar y eliminar.

Supongamos de aplicarlo contra la entidad de Heroe.

  • hero: Entidad que contiene su configuracion.
    
    import { ClassConfig, FieldType } from 'projects/hg-angular/src/public-api';
    import { Superpower } from './superpower';

    export class Hero {
        id: number;
        name: string;
        powers?: Superpower[];

        public static getClassConfig(): ClassConfig {
            return {
                entityName: 'Heroes',
                idKeys: ['id'],
                fieldConfig: [
                    {
                    key: 'id',
                    display: 'Identificador',
                    isColumn: true,
                    isFilter: false,
                    typeFilter: FieldType.inputText
                },{
                    key: 'name',
                    display: 'Nombre',
                    isColumn: true,
                    isFilter: true,
                    typeFilter: FieldType.inputText
                },{
                    key: 'powers',
                    display: 'Superpoderes',
                    isColumn: false,
                    isFilter: false,
                    typeFilter: FieldType.select,
                    url: 'http:localhost:8080/selects/superpowers'
                }]
            }
        }
    }
  • hero.service : Servicio desde donde se van a ejecutar las acciones sobre el web service.
import { Injectable } from '@angular/core';
import { Hero } from './hero';
import { HttpClient } from '@angular/common/http';
import { LoadService, MessageService, GenericService } from 'projects/hg-angular/src/public-api';


@Injectable({
  providedIn: 'root'
})
export class HeroService extends GenericService<Hero> {
  url: string;

  constructor(httpClient: HttpClient, loadService: LoadService, messageService: MessageService) {
    super(httpClient, loadService, messageService);
    this.url = '/heroes';
  }

}
  • hero-form.component: Con este formulario se va a dar de alta y modificar una entidad. ts
import { Component, OnInit, Inject } from '@angular/core';
import { ClassConfig } from 'hg-angular/public-api';
import { Hero } from '../hero';
import { MatDialogRef, MAT_DIALOG_DATA } from '@angular/material';
import { HeroService } from '../hero.service';

@Component({
  selector: 'app-hero-form',
  templateUrl: './hero-form.component.html',
  styleUrls: ['./hero-form.component.sass']
})
export class HeroFormComponent implements OnInit {

  classConfig: ClassConfig = Hero.getClassConfig();
  entity: Hero = new Hero();
  selects: any = {};
  isUpdate: boolean;
  constructor(public dialogRef: MatDialogRef<HeroFormComponent>,
              @Inject(MAT_DIALOG_DATA) public id: any,
              public service: HeroService) { }

  ngOnInit() {
  }
  setEntity(ent) {
    this.entity = ent;
    this.isUpdate = true;
  }
  display(key): string {
    const el = this.classConfig.fieldConfig.find(field => field.key === key);
    return el != null ? el.display : '';
  }

}

HTML

<hg-form
  [classConfig]="this.classConfig"
  [service]="this.service"
  [entity]="this.entity"
  (setEntity)="this.setEntity($event)"
  [entityForm]="entityForm"
  [dialogRef]="this.dialogRef"
  [id]="this.id"
>
  <form #entityForm="ngForm">
    <div fxLayout="row" fxLayoutAlign="start center">
      <div fxLayout="column" fxFlex="100">
        <mat-form-field>
            <input id="name" name="name"  [(ngModel)]="entity.name" required="true" matInput
            [placeholder]="display('name')"
            #name="ngModel">
          <mat-error *ngIf="name.errors?.required">
            Debe ingresar el nombre
          </mat-error>
        </mat-form-field>
      </div>
    </div>
  </form>
</hg-form>
  • hero-crud.component: Listado de entidades ts
import { Component, OnInit } from '@angular/core';
import { ClassConfig } from 'hg-angular/public-api';
import { Hero } from '../hero';
import { HeroService } from '../hero.service';
import { HeroFormComponent } from '../hero-form/hero-form.component';

@Component({
  selector: 'app-hero-crud',
  templateUrl: './hero-crud.component.html',
  styleUrls: ['./hero-crud.component.sass']
})
export class HeroCrudComponent implements OnInit {
  classConfig: ClassConfig = Hero.getClassConfig();
  classForm = HeroFormComponent;

  constructor(public service: HeroService) { }

  ngOnInit() {
  }

}

HTML

<hg-crud
 [classConfig]="classConfig" [service]="service"
 [dialogClass]="classForm"
 >
</hg-crud>

Configuración de Clase

La configuración de clase de una entidad es el elemento central sobre el cual se crearon los demas desarrollos genericos. Esta configuración contiene desde el nombre de la entidad hasta el tipo de cada uno de los campos de la entidad. Cada una de las entidades que se quieran mostrar con los componentes debe tener definido el metodo estatico getClassConfig() : ClassConfig que va a retornar su configuración particular

Clases

ClassConfig

AtributosTipoObservaciones
entityNameStringTexto estatico que será el nombre con el cual se presentará la entidad. Por ejemplo el entityName de una entidad Person es 'Persona'.
orderFilter?string[]Arreglo de String que contiene el nombre los atributos y el orden en el que se van a mostrar en el selector de atributos a filtrar
idKeysstring[]Arreglo que contiene el nombre de los atributos que forman la clave primaria o Id de la entidad
deleteKeys?string[]Arreglo que contiene los atributos que se van a mostrar en un cartel de confirmación de eliminación de un elemento
fieldConfigFieldConfigHGeneric[]Arreglo con toda la configuración de cada uno de los campos de la entidad en cuestion

FieldConfigHGeneric

AtributosTipoObservaciones
keystringNombre del campo en la entidad. Por ejemplo si tenemos la clase Person en TypeScript que tiene el atributo de clase name entonces la key debe ser el string 'name'
displayStringEs el texto con el que se va a presentar ese campo al usuario final. Siguiendo el ejemplo de Persona cuyo campo se llama name entonces un buen valor para display sería el string 'Nombre de Persona'
isColumnBooleanCampo booleano que va a indicar si el campo en cuastion se va a mostrar al usuario o no, en la tabla generica o en otro componente generico.
isFilterBooleanCampo booleano que va a indicar si ese campo va a ser el valor de un filtro o no.
typeFilterFieldTypeEste campo es el tipo de filtro que se va a pintar en el formulario de filtros del componente Filtro Generico. Dependiendo del valor de este atributo se va a pintar un input del tipo texto o númerico o un select, etc
url?stringEn caso de ser un campo de tipo select el que se va a pintar en un filtro. Se puede usar esta propiedad para indicarle al componente de filtro que debe ir a buscar la información del select de un servicio rest que debe ser un get
options?any[]En caso de ser un campo de tipo select simple se puede usar esta propiedad para indicarle los valores que se van a mostrar. Un ejemplo es el select del sexo de una persona que siempre van a ser dos valores 'Masculino' y 'Femenino'. Otro uso de este atributo es para los datos de tipo booleano que se desean mostrar de una forma especifica en el componente que los muestre. En este caso se van a levantar los dos primeros valores como los representativos del mismo. Siendo el valor en la posición 0 del arreglo para el valor True y el contenido de la posición 1 es como se va a mostrar el valor False del atributo en cuestion. Un ejemplo es si queremos indicar si una persona esta casada o no y tenemos el campo isMarried en la clase y queremos mostrar los valores 'Si' cuando sea True y 'No' cuando sea False, entonces este campo debe contener el arreglo 'Si', 'No'. Adicionalmente en las tablas como en otros componentes se puede enviar HTML para pintar el campo a conveniencia.
optionsCheck?any[]Atributo auxiliar para uso exclusivo e interno del filtro generico

FieldType

Esta clase es un enumerador y los valores son los siguientes:

ValoresObservaciones
inputTextEste enumerador va a indicar que el campo es del tipo texto, para trabajarlo como tal en html
inputNumberEste enumerador va a indicar que el campo es del tipo número.
inputPasswordEste enumerador va a indicar que el campo es del tipo privado.
radioButtonEste enumerador va a indicar que el campo es un radio button. Se va a requerir del atributo ClassConfig.options o url para mostrar sus valores
textareaEste enumerador va a indicar que el campo es del tipo texto y que la entrada es de una longitud considerable.
selectEste enumerador va a indicar que el valor del campo se debe ingresar desde un selector de opciones. Por lo tanto tiene un número finito de opciones y que se tienen que recuperar ya sea desde la ClassConfig.url o de manera estatica de ClassConfig.options.
dateEste enumerador va a indicar que el valor del campo es una fecha y se le debe aplicar filtros para mostrarlas en el formato correcto. El ingreso del valor será un DatePicker.
fileEste enumerador va a indicar qeu el valor de entrada es un archivo. Aún no esta soportado por los componentes genericos
checkEste enumerador va a indicar que el valor es un dato booleano.

Ejemplo

Este ejemplo es sobre la clase Hero donde tenemos el nombre del heroe su identificador y superpoderes.

    
    import { ClassConfig, FieldType } from 'projects/hg-angular/src/public-api';
    import { Superpower } from './superpower';

    export class Hero {
        id: number;
        name: string;
        powers?: Superpower[];

        public static getClassConfig(): ClassConfig {
            return {
                entityName: 'Heroes',
                idKeys: ['id'],
                fieldConfig: [
                    {
                    key: 'id',
                    display: 'Identificador',
                    isColumn: true,
                    isFilter: false,
                    typeFilter: FieldType.inputText
                },{
                    key: 'name',
                    display: 'Nombre',
                    isColumn: true,
                    isFilter: true,
                    typeFilter: FieldType.inputText
                },{
                    key: 'powers',
                    display: 'Superpoderes',
                    isColumn: false,
                    isFilter: false,
                    typeFilter: FieldType.select,
                    url: 'http:localhost:8080/selects/superpowers'
                }]
            }
        }
    }

Componentes

Filtro Generico

Este componente generá filtros de una entidad según su configuración de clase. El formulario de filtros se generará en base a la configuración de cada campo. Por ejemplo si un campo tiene como typeFilter el tipo TypeFilter.inputText, entonces el filtro para ese campo sera un input del tipo texto y asi. Este componente esta compuesto de la siguiente manera:

        (*1)                                                                                                 
 Búscar ${entityName} por filtro                                                                         
 (*2)                          (*3)                            (*4)            (*5)                                      
 +------------------------+   +------------------------+      +--------------+ +------------------------+
 | Seleccionar campo    V |   | ${Input dinamico}      |      | Boton Búscar | | Boton Limpiar Filtros  |
 +------------------------+   +------------------------+      +--------------+ +------------------------+
  • Referenicias:
    1. Es el nombre de la entidad recuperada del campo ClassConfig.entityName.
    2. El seleccionador de campos es un select donde se muestran todos los valores del atributo ClassConfig.fieldConfig.*.display, es decir el campo display de cada uno de los elementos del arreglo fieldConfig.
    3. En este espacio se va a poner el elemento que corresponda. Ya sea un DatePicker para un campo del tipo fecha, un input texto para otro del tipo string y asi.
    4. Este boton es el que libera el evento de busqueda e indica al componente que lo use que los valor a filtrar cambiaron, asi tambien envia toda la información del nuevo filtro.
    5. Elimina todos los valores de los filtros.

Inputs de Filtro Generico

  • Configuración de clase: La configuración de clase es una instancia de ClassConfig y es donde se obtienen toda la información necesaria para mostrarla y crear los inputs genericos.

Modo de uso:

    <hg-filter #gFilter [classConfig]="classConfig"></hg-filter>

Tabla Generica

Esta tabla esta diseñada para poder adaptarse y presentar cualquier tipo de información. Para poder usar está tabla se debe ingresar los siguientes elementos como "input":

  • Instancia del service a usar: Es una instancia de un servicio angular que herede de la superclase GenericService<?>. Este servicio se debe inyectar en el componente que utilice La tabla generica. La tabla generica útiliza una instancia de GenericService de una cierta entidad para traer sus datos.
    +------------------------+          +-----------------------------+                                                  
    |                        |          |                             |                                         
    |    Tabla Generica      |          |       GenericService<E>     |                                         
    |                        |          |                             |                                         
    +------------^-----------+          +--------------^--------------+                                         
                 |                                     |                                                        
                 |Envia instancia                      |Hereda Funcionalidades                                  
                 |de ServiceE                          |                                                        
                 |                                     |                                                        
    +------------|-----------+              +----------|----------+                  +-------------------------+
    |                        |  Se Inyecta  |                     |  Solicita Datos  |                         |
    |  Componente que        <---------------       ServiceE      -------------------|       Web Service       |
    |  Usa tabla Generica    |              |                     |                  |                         |
    +------------------------+              +---------------------+                  +-------------------------+
  • Configuración de clase: La configuración de clase es una instancia de ClassConfig y es donde se obtienen toda la información necesaria para mostrar la información de cada campo de una cierta entidad.
  • Opcional Filtro: es una instancia del componente de hg-filter. De esta manera se va a vincular con la tabla para indicarle cuando se filtre o no un dato y mostrar los elementos filtrados.
  • Opcional Acciones: Se entiende por acción a las acciones que se desean realizar por cada elemento de la tabla. Un ejemplo puede ser: ver el detalle, editar el elemento, etc. Cada una de las acciones se va a corresponder con un boton en la tabla en la columna de Acciones. El input del componente es un Arreglo de ActionConfig
AtributoObservaciónes
eventInstancia de @angular/core/EventEmitter que es la que va a tener la función que manejará el click del botón.
textTexto estatic que va a ser el contenido del boton
textResolver?Función que recibe como parametro el elemento y retorna el texto del boton. Se va a invocar cada vez que cambie el elemento.
colorResolver?Función que recibe como parametro el elemento y puede retornar el color del boton. Siendo los colores posibles 'warn', 'accent', 'primary' o 'none'.

Ejemplos

  • heroes.component.html
    <hg-filter #gFilter [fieldConfig]="classConfig"></hg-filter>
    
    <hg-table 
        #tabservice 
        [gFilter]="gFilter" 
        [classConfig]="classConfig" 
        [service]="service" 
        [actions]="actions">
    </hg-table>
  • heroes.component.ts
import { Component, EventEmitter } from '@angular/core';
import { Hero } from './hero';
import { HeroService } from './hero.service';
import { ClassConfig, ActionConfig, MessageService } from 'projects/hg-angular/src/public-api';
import { MatDialog } from '@angular/material';
import { ConfigSuperpowerComponent } from './config-superpower/config-superpower.component';

@Component({
  selector: 'app-heroes',
  templateUrl: './app.component.html',
  styleUrls: ['./app.component.scss'],
})
export class HeroesComponent {
  classConfig: ClassConfig = Hero.getClassConfig();
  actions: ActionConfig[];
  
  constructor(public service: HeroService, private messageSerivce: MessageService, private dialog: MatDialog) {
    // Creción del evento de Carteles
    let dialogs = new ActionConfig();
    dialogs.event = new EventEmitter();
    // Se subscribe la funcion que se va a ejecutar al click del boton
    dialogs.event.subscribe((hero) => this.detail(hero));
    // Se agrega el texto del boton
    dialogs.text = 'Carteles';
    // Se agrega un color al boton, adicionalmente puede cambiar según los atributos del heroe
    dialogs.colorResolver = (hero) => {
      return 'accent'
    }
    let superpowers = new ActionConfig();
    superpowers.event = new EventEmitter();
    superpowers.event.subscribe((hero) => this.powerConfig(hero));
    superpowers.text = 'Super Poderes';
    this.actions = [superpowers, dialogs];
  }
  detail(hero: Hero) {

    .....
    ....

  }
  powerConfig(hero) {
     ...
     ....
  }
}
  • heroes.service.ts
import { Injectable } from '@angular/core';
import { Hero } from './hero';
import { HttpClient } from '@angular/common/http';
import { LoadService, MessageService, GenericService } from 'projects/hg-angular/src/public-api';


@Injectable({
  providedIn: 'root'
})
export class HeroService extends GenericService<Hero> {
  url: string;

  constructor(httpClient: HttpClient, loadService: LoadService, messageService: MessageService) {
    super(httpClient, loadService, messageService);
    this.url = '/heroes';
  }

}

Drag & Drop

Carteles

Message service

Este servicio de mensajes es el que centraliza todos los llamados a los carteles de alerta, dialogo, etc. Gracias a este servicio podemos mantener un unico estilo de carteles, alertas y formas para todas las aplicaciónes, pre construidos.

MetodoParametrosRetornoObservaciones

Indicadores de carga de información

Load service

Este servicio expone distintos metodos a los cuales se deben subscribir para poder reconocer cuando se esta ejecutando un request cualquiera y cuando termina. Esta pensado para que se indique al usuario de alguna manera que su pedido esta siendo procesado y que se esta esperando una respuesta del servicio web.

MetodoParametrosRetornoObservaciones

Code scaffolding

Run ng generate component component-name --project hg-angular to generate a new component. You can also use ng generate directive|pipe|service|class|guard|interface|enum|module --project hg-angular.

Note: Don't forget to add --project hg-angular or else it will be added to the default project in your angular.json file.

Build

Run ng build hg-angular to build the project. The build artifacts will be stored in the dist/ directory.

Publishing

After building your library with ng build hg-angular, go to the dist folder cd dist/hg-angular and run npm publish.

Running unit tests

Run ng test hg-angular to execute the unit tests via Karma.

Further help

To get more help on the Angular CLI use ng help or go check out the Angular CLI README.