Your Web News in One Place

Help Webnuz

Referal links:

Sign up for GreenGeeks web hosting
April 6, 2022 07:30 am GMT

Usando directivas de Angular para extender componentes de terceros

Traduccin en espaol del artculo original de Tim Deschryver publicado el 11 marzo 2022

Las directivas en Angular son poco usadas y yo creo que es porque nosotros no sabemos todo de lo que son capaces de hacer. Si utilizas Angular t probablemente se te har familiar las directivas estructurales como *ngIf y ngFor, pero debera tu cdigo contener directivas propias?

La respuesta a esa pregunta es probablemente que no, y si en caso de, t lo has resuelto empleando componentes en vez de una directiva porque estos son ms familiares.

En este artculo, yo quiero mostrarte una tcnica usando las directivas para configurar componentes de terceros de forma unificada, Yo considero est como una solucin elegante en comparacin de utilizar un componente contenedor.

Vamos a mirar el ejemplo:

Directiva por defecto

En mi proyecto usamos el componente p-calendar de PrimeNG y como podemos ver el siguiente cdigo se repite cada vez.

<p-calendar  [(ngModel)]="date"  required  id="date"  name="date"  dateFormat="dd/mm/yy"  [showIcon]="true"  [showButtonBar]="true"  [monthNavigator]="true"  [yearNavigator]="true"  yearRange="1900:2050"  [firstDayOfWeek]="1"></p-calendar>

Este markup es requerido para configurar el componente del modo que queremos por defecto. Y si me preguntas que todo este cdigo no solo ensucia el cdigo, sino tambin confunde y engaa, haciendo creer que las cosas son ms complejas de lo que son en realidad. Yo puedo olvidar (O no saber que tengo) que agregar un atributo al p-calendar y este se comporta de otra manera para el usuario.

Adems, cuando el componente, elimina, cambia o agrega un nuevo atributo, yo tendra que cambiar todos los p-calendar en nuestro cdigo. En resumen, esto tiene impacto en nuestros developers y tambin en los usuarios.

Cuando nosotros refactorizamos el cdigo utilizando una directiva, el template se vuelve ms simple y nos aseguramos de siempre brindar la misma experiencia al usuario.

La versin final seria:

<p-calendar [(ngModel)]="date" required id="date" name="date"></p-calendar>

Pero como hemos pasado de 14 lneas de HTML a nicamente una, la respuesta es usando una directiva.

La directiva emplea el selector de p-calendar, para buscar modificar todos los elementos de p-calendar e inyectamos el calendar en la directiva, configurndolo como nosotros necesitamos.

calendar.directive.tsimport { Directive } from '@angular/core';import { Calendar } from 'primeng/calendar';@Directive({    selector: 'p-calendar',})export class CalenderDirective {    constructor(private calendar: Calendar) {        this.calendar.dateFormat = 'dd/mm/yy';        this.calendar.showIcon = true;        this.calendar.showButtonBar = true;        this.calendar.monthNavigator = true;        this.calendar.yearNavigator = true;        this.calendar.yearRange = '1900:2050';        this.calendar.firstDayOfWeek = 1;    }}

Cambiando la configuracin por defecto

La directiva que hemos creado aplica esa configuracin a todos los <p-calendars, pero podemos tener algn caso que esto no aplique, para eso podemos sobreescribir los valores predefinidos en aquellos que requieren algo diferente.

En el siguiente ejemplo, podemos desactivar la opcin de navegacin asignndole a las propiedades el valor a falso.

<p-calendar [monthNavigator]="false" [yearNavigator]="false"></p-calendar>

Directiva selectiva

En vez que una directiva que cambia el comportamiento de todos los elementos, podemos modificar el selector para elementos especficos y tengas diferentes casos de uso.

Por ejemplo, tenemos un dropdown que tiene un contrato genrico y queremos afectar solos los que coincidan con selector p-dropdown[codes], estos pueden ser configurados. Notar que tenemos el atributo codes en el selector para nicamente afectar estos elementos.

import { Directive, OnInit } from '@angular/core';import { Dropdown } from 'primeng/dropdown';import { sortByLabel } from '@core';@Directive({    selector: 'p-dropdown[codes]',})export class CodesDropdownDirective implements OnInit {    constructor(private dropdown: Dropdown) {        this.dropdown.optionLabel = 'label';        this.dropdown.optionValue = 'key';        this.dropdown.showClear = true;    }    public ngOnInit(): void {        this.dropdown.options = [...this.dropdown.options].sort(sortByLabel);        if(this.dropdown.options.length > 10) {            this.dropdown.filter = true;            this.dropdown.filterBy = 'label';            this.dropdown.filterMatchMode = 'startsWith';        }    }}

De esta manera, nicamente los p-dropdown que tenga el atributo codes, se comportan y se modifican con la directiva anterior y para utilizar solamente tenemos que agregar el atributo codes.

<p-dropdown [(ngModel)]="favoriteSport" codes required id="sport" name="sport"></p-dropdown>

Directiva excluyente

Otra es agregar el pseudo selector :not(), en nuestra directiva, para que aplique la configuracin para todos los casos comunes, pero excluyendo aquellos con el atributo resetDropdown.

Por ejemplo, el 90% de nuestros dropdown de los elementos dropdown en nuestra aplicacin tiene un datasource con "codes", no queremos tener que agregar el atributo codes al 90% de los elementos, otra manera solo agregar la directiva al 10% restante.

En vez usar el atributo codes para marcar los dropdown, nosotros asumimos que es el comportamiento por defecto, pero usando el atributo resetDropdown para excluir el comportamiento.

import { Directive, OnInit } from '@angular/core';import { Dropdown } from 'primeng/dropdown';import { sortByLabel } from '@core';@Directive({    selector: 'p-dropdown:not(resetDropdown)',})export class CodesDropdownDirective implements OnInit {    constructor(private dropdown: Dropdown) {        this.dropdown.optionLabel = 'label';        this.dropdown.optionValue = 'key';        this.dropdown.showClear = true;    }    public ngOnInit(): void {        this.dropdown.options = [...this.dropdown.options].sort(sortByLabel);        if(this.dropdown.options.length > 10) {            this.dropdown.filter = true;            this.dropdown.filterBy = 'label';            this.dropdown.filterMatchMode = 'startsWith';        }    }}

En el HTML, empleara de la siguiente manera.

<!-- Usando la directiva codes por defecto --><p-dropdown [(ngModel)]="favoriteSport" required id="sport" name="sport"></p-dropdown><!-- Excluyendo el p-dropdown porque contiene el atributo resetDropdown --><p-dropdown  [(ngModel)]="preference"  resetDropdown  required  id="preference"  name="preference"></p-dropdown>

Directivas para cargar datos

Nosotros podemos hacer an ms con la directiva, por ejemplo podemos ver como una directiva funciona como fuente de datos para llenar un dropdown con datos.

Esto es muy til para datasources que se repiten o se utilizan con frecuencia y a su vez hacer que el datasource sea configurable.

En el siguiente ejemplo, nosotros agregamos el atributo countries, para hacer el binding a los dropdown que utilizan la lista de countries como datasources. Esta directiva puede usarse con anidadas con otras, adems incluye un @Ouput() para emitir un evento cuando los countries estn cargados.

import { Directive, EventEmitter, OnInit, Output } from '@angular/core';import { Dropdown } from 'primeng/dropdown';import { GeoService, sortByLabel } from '@core';@Directive({    selector: 'p-dropdown[countries]',})export class CountriesDropdownDirective implements OnInit {    @Output() loaded = new EventEmitter<ReadonlyArray<Countries>>();    constructor(private dropdown: Dropdown, private geoService: GeoService) {}    public ngOnInit(): void {        this.geoService.getCountries().subscribe((result) => {            this.dropdown.options = result.map((c) => ({ label: c.label, key: c.id })).sort(sortByValue);            this.loaded.emit(this.dropdown.options);        });    }}

Ahora usamos la directiva

<p-dropdown  [(ngModel)]="country"  countries  required  id="country"  name="country"  (loaded)="countriesLoaded($event)"></p-dropdown>


`

Resumen

Las directivas de Angular son muy poderosas, pero tristemente poco utilizadas.

Las directivas cumplen con el principio Open-closed. El componente es cerrado para modificaciones, pero las directivas nos permiten extender el componente sin realizar cambios a lo interno.

Por ejemplo, con las directivas podemos modificar el comportamiento de componentes de terceros o de una librera que no tenemos acceso al cdigo del componente.

Es cierto que podemos lograr lo mismo empleando un componente contenedor y con componentes que tienes configuraciones complejas o muchas opciones, pero esto requiere ms cdigo y es difcil de mantener.

Enfocarnos en los elementos que requieren unos comportamientos o configuracin diferente, nosotros podemos aprovecharnos de utilizar los selectores para elegir esos elementos especficos, y como las directivas se pueden anidar podemos limitar esa responsabilidad para que haga una sola cosa.

Thanks to @timdeschryver

Opinin personal

Las siguientes lineas no son parte del post original.

Desde mi punto de vista, utilizar las directivas nos permite mucha flexibilidad al trabajar con componentes de terceros o libreras, podemos lograr encapsular ciertos casos sin modificar el comportamiento original.

La parte de cargar datos utilizando una directiva es algo muy poderoso y hace muy flexible nuestro cdigo.


Original Link: https://dev.to/danyparedes/usando-directivas-de-angular-para-extender-componentes-de-terceros-4eek

Share this article:    Share on Facebook
View Full Article

Dev To

An online community for sharing and discovering great ideas, having debates, and making friends

More About this Source Visit Dev To