Buscar..


Introducción

El tubo | el carácter se utiliza para aplicar tuberías en Angular 2. Las tuberías son muy similares a los filtros en AngularJS, ya que ambas ayudan a transformar los datos en un formato específico.

Parámetros

Función / Parámetro Explicación
@Pipe ({nombre, puro}) Metadatos para tubería, debe preceder inmediatamente a la clase de tubería.
nombre: cadena lo que usarás dentro de la plantilla
puro: booleano el valor predeterminado es verdadero, marque esto como falso para que su tubería sea reevaluada con más frecuencia
transformar (valor, args []?) La función que se llama a transformar los valores en la plantilla.
valor: cualquiera El valor que quieres transformar.
Args: cualquiera [] Los argumentos que puede necesitar incluir en su transformación. Marque args opcionales con el? operador como tal transformar (valor, arg1, arg2?)

Observaciones

Este tema trata sobre Angular2 Pipes , un mecanismo para transformar y formatear datos dentro de plantillas HTML en una aplicación Angular2.

Tuberías de encadenamiento

Las tuberías pueden estar encadenadas.

<p>Today is {{ today | date:'fullDate' | uppercase}}.</p>

Tubos personalizados

my.pipe.ts

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

@Pipe({name: 'myPipe'})
export class MyPipe implements PipeTransform {

  transform(value:any, args?: any):string {
    let transformedValue = value; // implement your transformation logic here
    return transformedValue;
  }

}

my.component.ts

import { Component } from '@angular/core';

@Component({
  selector: 'my-component',
  template: `{{ value | myPipe }}`
})
export class MyComponent {

    public value:any;

}

my.module.ts

import { NgModule } from '@angular/core';
import { BrowserModule } from '@angular/platform-browser';

import { MyComponent } from './my.component';
import { MyPipe } from './my.pipe';

@NgModule({
  imports: [
    BrowserModule,
  ],
  declarations: [
    MyComponent,
    MyPipe
  ],
})
export class MyModule { }

Tubos incorporados

Angular2 viene con algunos tubos integrados:

Tubo Uso Ejemplo
DatePipe date {{ dateObj | date }} // output is 'Jun 15, 2015'
UpperCasePipe uppercase {{ value | uppercase }} // output is 'SOMETEXT'
LowerCasePipe lowercase {{ value | lowercase }} // output is 'sometext'
CurrencyPipe currency {{ 31.00 | currency:'USD':true }} // output is '$31'
PercentPipe percent {{ 0.03 | percent }} //output is %3

Hay otros. Busque aquí su documentación.

Ejemplo

hotel-booking.component.ts

import { Component } from '@angular/core';

@Component({
    moduleId: module.id,
    selector: 'hotel-reservation',
    templateUrl: './hotel-reservation.template.html'
})
export class HotelReservationComponent {
    public fName: string =  'Joe';
    public lName: string = 'SCHMO';
    public reservationMade: string = '2016-06-22T07:18-08:00'
    public reservationFor: string = '2025-11-14';
    public cost: number = 99.99;
}

hotel-reservation.template.html

<div>
    <h1>Welcome back {{fName | uppercase}} {{lName | lowercase}}</h1>
    <p>
        On {reservationMade | date} at {reservationMade | date:'shortTime'} you 
        reserved room 205 for {reservationDate | date} for a total cost of 
        {cost | currency}.
    </p>
</div>

Salida

Welcome back JOE schmo
On Jun 26, 2016 at 7:18 you reserved room 205 for Nov 14, 2025 for a total cost of 
$99.99.

Depuración Con JsonPipe

El JsonPipe se puede usar para depurar el estado de cualquier interno dado.

Código

@Component({
  selector: 'json-example',
  template: `<div>
    <p>Without JSON pipe:</p>
    <pre>{{object}}</pre>
    <p>With JSON pipe:</p>
    <pre>{{object | json}}</pre>
  </div>`
})
export class JsonPipeExample {
  object: Object = {foo: 'bar', baz: 'qux', nested: {xyz: 3, numbers: [1, 2, 3, 4, 5]}};
}

Salida

Without JSON Pipe:
object
With JSON pipe:
{object:{foo: 'bar', baz: 'qux', nested: {xyz: 3, numbers: [1, 2, 3, 4, 5]}}

Tubería personalizada disponible a nivel mundial

Para hacer que una tubería personalizada esté disponible en toda la aplicación, Durante la aplicación bootstrap, extienda PLATFORM_PIPES.

import { bootstrap }    from '@angular/platform-browser-dynamic';
import { provide, PLATFORM_PIPES } from '@angular/core';

import { AppComponent } from './app.component';
import { MyPipe } from './my.pipe'; // your custom pipe

bootstrap(AppComponent, [
  provide(PLATFORM_PIPES, {
            useValue: [
                MyPipe 
            ],
            multi: true
        })
]);

Tutorial aquí: https://scotch.io/tutorials/create-a-globally-available-custom-pipe-in-angular-2

Creación de tubería personalizada

app / pipes.pipe.ts

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

@Pipe({name: 'truthy'})
export class Truthy implements PipeTransform {
  transform(value: any, truthy: string, falsey: string): any {
    if (typeof value === 'boolean'){return value ? truthy : falsey;}
    else return value
  }
}

app / my-component.component.ts

import { Truthy} from './pipes.pipe';

@Component({
  selector: 'my-component',
  template: `
    <p>{{value | truthy:'enabled':'disabled' }}</p>
  `,
  pipes: [Truthy]
})
export class MyComponent{ }

Desenvolver valores asíncronos con una tubería asíncrona

import { Component } from '@angular/core';
import { Observable } from 'rxjs/Observable';
import 'rxjs/add/observable/of';

@Component({
  selector: 'async-stuff',
  template: `
    <h1>Hello, {{ name | async }}</h1>
    Your Friends are:
    <ul>
      <li *ngFor="let friend of friends | async">
        {{friend}}
      </li>
    </ul>
  `
})
class AsyncStuffComponent {
  name = Promise.resolve('Misko');
  friends = Observable.of(['Igor']);
}

Se convierte en

<h1>Hello, Misko</h1>
Your Friends are:
<ul>
  <li>
    Igor
  </li>
</ul>

Extendiendo una tubería existente

import { Pipe, PipeTransform } from '@angular/core';
import { DatePipe } from '@angular/common'


@Pipe({name: 'ifDate'})
export class IfDate implements PipeTransform {
  private datePipe: DatePipe = new DatePipe();

  transform(value: any, pattern?:string) : any {
    if (typeof value === 'number') {return value}
    try {
      return this.datePipe.transform(value, pattern)
    } catch(err) {
      return value
    }
  }
}

Tubos de estado

Angular 2 ofrece dos tipos diferentes de tuberías: sin estado y con estado. Las tuberías son sin estado por defecto. Sin embargo, podemos implementar tuberías con estado estableciendo la propiedad pure en false . Como puede ver en la sección de parámetros, puede especificar un name y declarar si la tubería debe ser pura o no, es decir, sin estado o sin estado. Mientras que los datos fluyen a través de una tubería sin estado (que es una función pura) que no recuerda nada, los datos pueden ser gestionados y recordados por tuberías con estado. Un buen ejemplo de una tubería con estado es el AsyncPipe proporcionado por Angular 2.

Importante

Observe que la mayoría de las tuberías deben caer en la categoría de tuberías sin estado. Esto es importante por razones de rendimiento, ya que Angular puede optimizar tuberías sin estado para el detector de cambios. Así que use las tuberías con estado con cautela. En general, la optimización de tuberías en Angular 2 tiene una mayor mejora de rendimiento sobre los filtros en Angular 1.x. En Angular 1, el ciclo de resumen siempre tuvo que volver a ejecutar todos los filtros aunque los datos no hayan cambiado en absoluto. En Angular 2, una vez que se ha calculado el valor de una tubería, el detector de cambios sabe que no debe volver a ejecutar esta tubería a menos que cambie la entrada.

Implementación de una tubería con estado.

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

@Pipe({
  name: 'countdown',
  pure: false
})
export class CountdownPipe implements PipeTransform, OnDestroy  {
  private interval: any;
  private remainingTime: number;

  transform(value: number, interval: number = 1000): number {
    if (!parseInt(value, 10)) {
      return null;
    }
    
    if (typeof this.remainingTime !== 'number') {
      this.remainingTime = parseInt(value, 10);
    }
    
    if (!this.interval) {
      this.interval = setInterval(() => {
        this.remainingTime--;
        
        if (this.remainingTime <= 0) {
          this.remainingTime = 0;
          clearInterval(this.interval);
          delete this.interval;
        }
      }, interval);
    }
    
    return this.remainingTime;
  }
  
  ngOnDestroy(): void {
    if (this.interval) {
      clearInterval(this.interval);
    }
  }
}

A continuación, puede utilizar la tubería como de costumbre:

{{ 1000 | countdown:50 }}
{{ 300 | countdown }}

Es importante que su tubería también implemente la interfaz OnDestroy para que pueda limpiar una vez que se destruya su tubería. En el ejemplo anterior, es necesario borrar el intervalo para evitar pérdidas de memoria.

Tubo dinámico

Escenario de caso de uso: una vista de tabla consta de diferentes columnas con diferentes formatos de datos que deben transformarse con diferentes canalizaciones.

table.component.ts

...
import { DYNAMIC_PIPES } from '../pipes/dynamic.pipe.ts';

@Component({
    ...
    pipes: [DYNAMIC_PIPES]
})
export class TableComponent {
    ...

    // pipes to be used for each column
    table.pipes = [ null, null, null, 'humanizeDate', 'statusFromBoolean' ],
    table.header = [ 'id', 'title', 'url', 'created', 'status' ],
    table.rows = [
        [ 1, 'Home', 'home', '2016-08-27T17:48:32', true ],
        [ 2, 'About Us', 'about', '2016-08-28T08:42:09', true ],
        [ 4, 'Contact Us', 'contact', '2016-08-28T13:28:18', false ],
        ...
    ]
    ...

}

dynamic.pipe.ts

import {
    Pipe,
    PipeTransform
} from '@angular/core';
// Library used to humanize a date in this example
import * as moment from 'moment';

@Pipe({name: 'dynamic'})
export class DynamicPipe implements PipeTransform {

    transform(value:string, modifier:string) {
        if (!modifier) return value;
        // Evaluate pipe string
        return eval('this.' + modifier + '(\'' + value + '\')')
    }

    // Returns 'enabled' or 'disabled' based on input value
    statusFromBoolean(value:string):string {
        switch (value) {
            case 'true':
            case '1':
                return 'enabled';
            default:
                return 'disabled';
        }
    }

    // Returns a human friendly time format e.g: '14 minutes ago', 'yesterday'
    humanizeDate(value:string):string {
        // Humanize if date difference is within a week from now else returns 'December 20, 2016' format
        if (moment().diff(moment(value), 'days') < 8) return moment(value).fromNow();
        return moment(value).format('MMMM Do YYYY');
    }
}

export const DYNAMIC_PIPES = [DynamicPipe];

table.component.html

<table>
    <thead>
        <td *ngFor="let head of data.header">{{ head }}</td>
    </thead>
    <tr *ngFor="let row of table.rows; let i = index">
        <td *ngFor="let column of row">{{ column | dynamic:table.pipes[i] }}</td>
    </tr>
</table>

Resultado

| ID | Page Title     | Page URL    | Created          | Status     |
---------------------------------------------------------------------
|  1 | Home           | home        | 4 minutes ago    | Enabled    |
|  2 | About Us       | about       | Yesterday        | Enabled    |
|  4 | Contact Us     | contact     | Yesterday        | Disabled   |
---------------------------------------------------------------------

Probando un tubo

Dada una tubería que invierte una cuerda.

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

@Pipe({ name: 'reverse' })
export class ReversePipe implements PipeTransform {
  transform(value: string): string {
    return value.split('').reverse().join('');
  }
}

Se puede probar configurando el archivo de especificaciones como este.

import { TestBed, inject } from '@angular/core/testing';

import { ReversePipe } from './reverse.pipe';

describe('ReversePipe', () => {
  beforeEach(() => {
    TestBed.configureTestingModule({
      providers: [ReversePipe],
    });
  });

  it('should be created', inject([ReversePipe], (reversePipe: ReversePipe) => {
    expect(reversePipe).toBeTruthy();
  }));

  it('should reverse a string', inject([ReversePipe], (reversePipe: ReversePipe) => {
    expect(reversePipe.transform('abc')).toEqual('cba');
  }));
});


Modified text is an extract of the original Stack Overflow Documentation
Licenciado bajo CC BY-SA 3.0
No afiliado a Stack Overflow