1. Introducción y Objetivos de Aprendizaje:

  • ¡Hola, desarrolladores! 👋 Hoy nos sumergiremos en una de las características más elegantes de Angular: los Pipes 💧. Imaginen que tienen datos crudos en su componente (una fecha 📅, un número #️⃣, un texto largo 📜), pero necesitan mostrarlos en la plantilla HTML con un formato específico (fecha corta, moneda 💰, texto abreviado). Los Pipes son los "transformadores" 🪄 que nos permiten hacer esto directamente en el HTML, de forma limpia y reutilizable.
  • Desde una perspectiva de arquitectura de software 🏗️, los Pipes son cruciales para adherirse al principio de Separación de Responsabilidades. La lógica de cómo mostrar los datos (formateo) pertenece a la capa de presentación (la plantilla), no necesariamente a la lógica de negocio del componente. Los Pipes encapsulan esta lógica de transformación ⚙️, haciéndola testeable ✅, reutilizable 🔄 y manteniendo los componentes más ligeros y enfocados en gestionar el estado y la interacción. Además, Angular optimiza el uso de Pipes (especialmente los "puros") para un rendimiento eficiente 🚀.
  • (Nota de Repaso): Al finalizar esta nota, usted podrá:
    • ✅ Definir qué es un Pipe en Angular y cuál es su propósito principal.
    • ✅ Identificar y utilizar los Pipes incorporados (built-in) más comunes de Angular.
    • ✅ Comprender cómo pasar argumentos a los Pipes para personalizar la transformación.
    • ✅ Encadenar múltiples Pipes para aplicar varias transformaciones secuencialmente.
    • ✅ Crear y utilizar sus propios Pipes personalizados (Custom Pipes).
    • ✅ Distinguir entre Pipes Puros e Impuros y entender sus implicaciones de rendimiento.
    • ✅ Aplicar Pipes correctamente en las plantillas HTML de Angular usando la sintaxis |.

2. Conceptos Fundamentales (Definiciones Clave):

  • Pipe 🔧: Una clase decorada con @Pipe que implementa la interfaz PipeTransform. Su función principal es transformar un valor de entrada en un valor de salida formateado para ser mostrado en una plantilla HTML.
  • Transformación 🔄: El proceso de convertir datos de un formato a otro (ej: objeto Date a string dd/MM/yyyy, número 1234.56 a string $1,234.56).
  • PipeTransform (Interfaz) 📝: Interfaz que debe implementar toda clase Pipe. Define un único método obligatorio: transform.
  • transform(value: any, ...args: any[]): any (Método) ✨: El corazón del Pipe. Recibe el valor original (value) que fluye desde la izquierda del operador | en la plantilla, y opcionalmente, argumentos adicionales (args) pasados después de dos puntos (:). Debe devolver el valor transformado.
  • Sintaxis en Plantilla (➡️ |): El operador "pipe" se usa en las expresiones de interpolación ({{ }}) o en los data bindings ([property]="expression | pipe") para aplicar un Pipe. {{ valor | nombreDelPipe }}.
  • Argumentos de Pipe (➡️ :): Se pasan argumentos adicionales al método transform usando dos puntos después del nombre del Pipe. {{ valor | nombreDelPipe:arg1:arg2 }}.
  • Encadenamiento de Pipes ⛓️: Aplicar múltiples Pipes secuencialmente. La salida de un Pipe se convierte en la entrada del siguiente. {{ valor | pipe1 | pipe2:arg1 }}.

3. Desarrollo del Tema: El Poder de los Pipes en Acción 🛠️

  • Piensen en los datos fluyendo a través de "tuberías" (pipes) en su plantilla 💧➡️💧➡️🖥️. Cada tubería toma el dato, le hace algo (lo formatea, lo filtra, lo modifica) y lo pasa al siguiente, o finalmente lo muestra en la pantalla.

  • Profundicemos en los detalles técnicos y casos de uso:

    A. ¿Por qué usar Pipes?

    • Legibilidad del Template: Mantiene las expresiones en HTML limpias. {{ fechaCumpleanos | date:'shortDate' }} vs {{ formatearFechaCorta(fechaCumpleanos) }}.
    • Reutilización: La lógica de formato es reutilizable en toda la app.
    • Separación de Responsabilidades: Componente (qué datos) vs Pipe (cómo mostrarlos).
    • Performance (Pipes Puros): Angular optimiza su ejecución 🚀.
    • Testabilidad: Fáciles de probar unitariamente 🧪.

    B. Cómo Llamar Pipes desde HTML 💻:

    • Sintaxis Básica: {{ expresionAngular | nombrePipe }}

      {{ titulo | uppercase }}
    • Con Argumentos ⚙️: {{ expresionAngular | nombrePipe:argumento1:argumento2:... }}

      Fecha: {{ fechaActual | date:'dd/MM/yyyy' }}

      Número: {{ numeroGrande | number:'1.2-2' }}
    • Encadenamiento ⛓️: {{ expresionAngular | pipe1 | pipe2:argPipe2 | pipe3 }}

      {{ descripcionLarga | slice:0:15 | uppercase }}...

    C. Pipes Incorporados (Built-in) Más Comunes:

    • 📅 DatePipe: Formatea fechas. {{ miFecha | date:'medium' }}.
    • 🅰️ UpperCasePipe: Convierte texto a MAYÚSCULAS. {{ texto | uppercase }}.
    • 🔡 LowerCasePipe: Convierte texto a minúsculas. {{ texto | lowercase }}.
    • 📖 TitleCasePipe: Convierte texto a Formato Título. {{ texto | titlecase }}.
    • #️⃣ DecimalPipe (number): Formatea números. {{ numero | number:'1.0-2' }}.
    • % PercentPipe: Formatea números como porcentajes. {{ 0.25 | percent }} (25%).
    • 💰 CurrencyPipe: Formatea números como moneda. {{ precio | currency:'USD':'symbol' }} ($1,234.56).
    • {} JsonPipe: Convierte objeto/array a JSON string (ideal para debug). {{ miObjeto | json }}.
    • ✂️ SlicePipe: Extrae sub-sección de array/string. {{ miArray | slice:1:3 }}.
    • 🔑 KeyValuePipe: Itera sobre objetos/Maps en *ngFor. *ngFor="let item of miObjeto | keyvalue".
    • ⏳/⚡️ AsyncPipe: Se suscribe/desuscribe a Observables/Promises. {{ miObservable$ | async }}.

    D. Creando Pipes Personalizados (Custom Pipes) 🔧:

    1. Generación (CLI) ⌨️: ng generate pipe nombre-del-pipe (ej: ng g p truncate).
    2. Implementación ✍️: Edita nombre-del-pipe.pipe.ts, implementa transform().

      // Ejemplo: truncate.pipe.ts
      import { Pipe, PipeTransform } from '@angular/core';
      
      @Pipe({ name: 'truncate', standalone: true })
      export class TruncatePipe implements PipeTransform {
        transform(value: string, limit: number = 20, trail: string = '...'): string {
          // ... (lógica de truncar) ...
          return value.length > limit ? value.substring(0, limit) + trail : value;
        }
      }
      
3.  Registro ✅:
        * Standalone Components: Importa en `imports: [..., TruncatePipe]`.
        * NgModules: Declara en `declarations: [...]`.
    4. Uso en Plantilla 💻: `{{ miTexto | truncate:100:' ->' }}`.

   Pipes Puros vs. Impuros:**
    * Pipes Puros 💧 (`pure: true` - por defecto):
        * Se ejecutan solo con cambios *puros* (primitivos o referencia de objeto).
        * Ventaja: Muy eficientes 🚀.
    * Pipes Impuros 🔥 (`pure: false`):
        * Se ejecutan en *cada* ciclo de detección de cambios.
        * Uso: Necesarios para cambios internos de objetos/arrays (sin cambio de referencia) o estado interno (ej: `AsyncPipe`, `JsonPipe`).
         Precaución: ⚠️ ¡Pueden impactar el rendimiento! Usar con moderación.

4. Ejemplo Completo 🧪:

// en tu componente.ts
import { Component } from '@angular/core';
import { CommonModule } from '@angular/common'; // Para pipes built-in
import { TruncatePipe } from './truncate.pipe'; // Custom pipe
import { Observable, interval } from 'rxjs';
import { map } from 'rxjs/operators';

@Component({
  selector: 'app-pipe-demo',
  standalone: true,
  imports: [CommonModule, TruncatePipe], // <-- Importados aquí
  template: `
    Demostración de Pipes 🧪

    📅 Fecha actual (completa): {{ ahora | date:'fullDate' }}
    📅 Fecha actual (corta): {{ ahora | date:'short' }}

    📖 Título Original: {{ libro.titulo }}
    🅰️ Título en Mayúsculas: {{ libro.titulo | uppercase }}
    ✂️ Título Truncado: {{ libro.titulo | truncate:15:'...' }} 

    💰 Precio: {{ libro.precio | currency:'EUR':'symbol':'1.2-2' }}
    % Descuento: {{ libro.descuento | percent:'1.0-0' }}

    {} Descripción (JSON Debug):
    {{ libro | json }}

    ✂️ Tags (Primeros 2):
    
      {{ tag | titlecase }}
    

    ⏳ Contador (Async Pipe): {{ contador$ | async }}
  `
})
export class PipeDemoComponent {
  ahora: Date = new Date();
  libro = { /* ... datos del libro ... */ };
  contador$: Observable<number> = interval(1000).pipe(map(i => i * 2));
}

5. Buenas Prácticas y Consideraciones Adicionales 👍:

*
* ✨ Prioriza Pipes Puros: Mejor rendimiento.
* ✨ Evita Lógica Compleja en Pipes: Mantenlos simples y enfocados.
* ✨ Reutilización: Crea Custom Pipes para lógica repetida.
* ✨ No Abuses del Encadenamiento: Puede reducir legibilidad.
* ✨ Cuidado con Pipes Impuros y *ngFor: Considera trackBy.
* 🌐 Internacionalización (i18n): Configura LOCALE_ID para DatePipe, CurrencyPipe, etc.

  • 👨‍🏫 ¡Revisa los Pipes built-in antes de crear uno! ¡Y prueba tus creaciones! 🧪

6. Resumen / Puntos Clave para el Repaso 📌:

  • Pipes: Transforman datos en plantillas (@Pipe, PipeTransform).
  • Propósito: Formateo, legibilidad, reutilización, separación.
  • Sintaxis: {{ valor | nombrePipe:arg1 }}. Encadenables (| pipe1 | pipe2).
  • Built-in: Date, Upper/Lower/TitleCase, number, Currency, Percent, Json, Slice, KeyValue, Async.
  • Custom Pipes: ng g p nombre, implementa transform(), importa/declara.
  • Puros (💧) vs. Impuros (🔥): Puros más eficientes, Impuros para casos específicos (¡cuidado!).

7. Preguntas de Autoevaluación 🤔:

  1. ❓ ¿Cuál es el beneficio principal de usar Pipes sobre métodos de componente para formato?
  2. ❓ Sintaxis para DatePipe con formato 'dd-MMM-yyyy'.
  3. ❓ ¿Qué significa "Pipe puro" y por qué importa?
  4. ❓ ¿Cuándo usarías AsyncPipe?
  5. ❓ Pasos para crear un Pipe addPrefix que añada "PRE:" a un string.