Usando Pipes para transformar datos
Tags: angular, typescript, javascript, webdev
Published: 2022-04-09 16:36:48

Cuando necesitamos que nuestras aplicaciones muestren una información de una forma solamente para la visualización, en Angular podemos hacerlo gracias a los Pipes.

Angular nos permite convertir valores para ser visualizados de una manera específica sin alterarlos, en pocas palabras los Pipes nos permite tomar un dato y retornarlo transformado de la manera que queremos.

> Una mala práctica comúnmente usada es utilizar un método en el template para convertirlo, para  esos escenarios siempre utiliza un Pipe.

Los Pipes trabajan en conjunto con nuestros templates en los componentes utilizando el operando `|` obteniendo la data de izquierda a la función pipe en la derecha y esta retorna el dato transformado.

Angular viene con una lista de pipes además nos permite crear nuestras propias pipes para que retorne lo que nos interesa.

> Puedes ver la lista de pipes [https://angular.io/api/common#pipes](https://angular.io/api/common#pipes)

La idea en este post es usar un pipe de angular y crear uno a nuestras necesidades.

## Usando el pipe currency
Suponemos que nos piden crear una interfaz en la cual muestre un listado de salarios, pero queremos ver los decimales y un formato de moneda.

```typescript
salaryRanges = [
    {
      title: 'developer',
      salary: 90000,
    },
    {
      title: 'nbaPlayer',
      salary: 139883,
    },
    {
      title: 'doctor',
      salary: 72000,
    },
  ];
```
Para visualizarlos en el html usamos la directiva `ngFor`, algo como esto.

```html
<ul>
  <li *ngFor="let profesional of salaryRanges">
    {{ profesional.title }}
    {{ profesional.salary }}
  </li>
</ul>
```
Inicialmente se visualizan de esta forma

```html
developer 90000
nbaPlayer 139883
doctor 72000
```
Para cambiar la salida utilizando el pipe currency este por defecto utiliza USD como formato, este le agregara el símbolo de $ además de los decimales.

```html
<ul>
  <li *ngFor="let profesional of salaryRanges">
    {{ profesional.title }}
    {{ profesional.salary | currency }}
  </li>
</ul>
```
Ahora el formato de salida sera de esta manera.

```html
developer $90,000.00
nbaPlayer $139,883.00
doctor $72,000.00
```
Perfecto, nuestros salarios se visualizan con un formato, pero que pasaria si quisiera poder convertir esos salarios a dolares o euros ? angular no tiene algo para esto... entonces creamos un Pipe custom!

> Nota una solucion no optima seria llamar un metodo, en el ngFor pasandole valor y haciendo el calculo pero esto no seria optimo.

## Creando el custom pipe.

Un pipe no es más que una clase de typescript que implementa la interfaz PipeTransform, vamos a crear nuestro pipe convertExchange este tomara el valor y lo divide por 55 para así hacer la conversión.

```typescript
import { Pipe, PipeTransform } from '@angular/core';

@Pipe({
  name: 'convertExchange'
})
export class ConvertToExchange implements PipeTransform {
  transform(value: any, args?: any): any {
    return value / 55
  }
}
```
> Recuerda que al crear el pipe debes registrarlo en tu AppModule.

Nosotros podemos utilizar pipes anidados, por ejemplo convertExchange para generar el cálculo y currency para darle el formato.

Actualizamos nuestro html y usamos ambas pipes
```html
{{ profesional.salary | convertToExchange | currency }}
```
Y el resultado final es 

```
developer $1,636.36
nbaPlayer $2,543.33
doctor $1,309.09
```
Perfecto, nuestro pipe es capaz de convertir y darles formato, pero que pasaría si quisiéramos que el monto de cálculo sea dinámico, por ejemplo conversión de EUROS a USD.

¡Vamos a hacer ajustes!

Primero vamos a crear un objecto con el listado de monedas 

```typescript
const currencyValues = {
  USD: 55,
  EURO: 75,
};
```
En el método transform agregamos un nuevo parámetro currency, este se utilizará para obtener el valor relacionado con la moneda y luego hacer el cálculo en el transform, en caso de que no exista lo divide entre 1.

El código final será algo como esto: 
```typescript
import { Pipe, PipeTransform } from '@angular/core';
const currencyValues = {
  USD: 55,
  EURO: 75,
};

@Pipe({
  name: 'convertToExchange'
})
export class ConvertToExchange implements PipeTransform {
  transform(value: any, currency: string): any {
    return value / this.getCurrencyValue(currency);
  }

  getCurrencyValue(currency) {
    return currencyValues[currency] | 1;
  }
}
```
Perfecto, nuestro pipe recibirá el tipo de moneda y hará el cálculo para la conversión.

Para enviar el valor solo tenemos que usar `:` después del pipe.

```
{{ profesional.salary | convertToExchange: 'USD' | currency }}
```
La salida final seria:

```html
developer $1,636.36
nbaPlayer $2,543.33
doctor $1,309.09
```
Perfect! Nuestro pipe permite recibir parámetros, pero ahora tenemos que cambiar de manera manual y si quisiéramos que el usuario elija el formato de moneda desde un select. ¡Vamos a eso!!

## Un poco más interactivo.

Creamos un select con el listado de monedas para el usuario pueda seleccionar, en el evento change actualizaremos  una propiedad nueva llamada currentCurrency utilizando un nuevo método llamado changeTo que por defecto será DOP que no existe, por tanto, retornara 1.

```html
<select (change)="changeTo($any($event.target).value)">
  <option value="USD">USD</option>
  <option value="EURO">EURO</option>
  <option selected>DOP</option>
</select>
```
En el componente creamos la propiedad y el método.

```typescript
currentCurrency = 'DOP';
changeTo(currency) {
    this.currentCurrency = currency;
  }
```
Ya lo siguiente será usar la nueva propiedad currentCurrency en el template como parámetro para nuestro pipe.

```html
<li *ngFor="let profesional of salaryRanges">
    {{ profesional.title }}
    {{ profesional.salary | convertToExchange: currentCurrency | currency }}
  </li>
```
## Final
En resumen, los pipes son muy poderosos, pero te recomiendo que mires la documentación oficial de angular, donde verás muchos más ejemplos.

> [https://angular.io/guide/pipes](https://angular.io/guide/pipes)

Puedes jugar con el [demo del proyecto en stackbliz](https://stackblitz.com/edit/angular-ivy-opaevp?file=src%2Fapp%2Fapp.component.html).


[Photo by T K on Unsplash](https://unsplash.com/s/photos/pipes?utm_source=unsplash&utm_medium=referral&utm_content=creditCopyText)