Angular 2
Pipes
Ricerca…
introduzione
Il tubo |
il carattere viene utilizzato per applicare i tubi in Angular 2. I tubi sono molto simili ai filtri in AngularJS in quanto entrambi aiutano a trasformare i dati in un formato specificato.
Parametri
Funzione / Parametro | Spiegazione |
---|---|
@Pipe ({nome, puro}) | i metadati per pipe, devono precedere immediatamente la classe di pipe |
nome: stringa | cosa userai all'interno del modello |
puro: booleano | il valore predefinito è true, contrassegnalo come falso per fare rivedere il pipe più spesso |
transform (value, args []?) | la funzione che viene chiamata per trasformare i valori nel modello |
valore: qualsiasi | il valore che desideri trasformare |
args: any [] | gli argomenti che potresti aver bisogno di includere nella tua trasformazione. Contrassegnare argomenti opzionali con il? operatore come tale trasforma (valore, arg1, arg2?) |
Osservazioni
Questo argomento copre Angular2 Pipes , un meccanismo per trasformare e formattare i dati all'interno di modelli HTML in un'applicazione Angular2.
Tubi concatenati
I tubi possono essere incatenati.
<p>Today is {{ today | date:'fullDate' | uppercase}}.</p>
Tubi personalizzati
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 { }
Tubi incorporati
Angular2 viene fornito con alcuni tubi incorporati:
Tubo | uso | Esempio |
---|---|---|
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 |
Ce ne sono altri Guarda qui per la loro documentazione.
Esempio
hotel-reservation.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>
Produzione
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.
Debugging con JsonPipe
JsonPipe può essere utilizzato per il debug dello stato di qualsiasi dato interno.
Codice
@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]}};
}
Produzione
Without JSON Pipe:
object
With JSON pipe:
{object:{foo: 'bar', baz: 'qux', nested: {xyz: 3, numbers: [1, 2, 3, 4, 5]}}
Tubo personalizzato disponibile a livello globale
Per rendere disponibile un'ampia gamma di applicazioni personalizzate, durante il bootstrap dell'applicazione, estendere 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 qui: https://scotch.io/tutorials/create-a-globally-available-custom-pipe-in-angular-2
Creazione di pipe personalizzate
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{ }
Scomporre i valori asincroni con il tubo asincrono
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']);
}
diventa:
<h1>Hello, Misko</h1>
Your Friends are:
<ul>
<li>
Igor
</li>
</ul>
Estensione di un tubo esistente
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
}
}
}
Stateful Pipes
Angular 2 offre due diversi tipi di tubi: stateless e stateless. I pipe sono stateless per impostazione predefinita. Tuttavia, possiamo implementare pipe stateful impostando la proprietà pure
su false
. Come puoi vedere nella sezione dei parametri, puoi specificare un name
e dichiarare se la pipe deve essere pura o no, ovvero statica o stateless. Mentre i dati fluiscono attraverso una pipe senza stato (che è una pura funzione) che non ricorda nulla, i dati possono essere gestiti e ricordati da pipe stateful. Un buon esempio di pipe stateful è AsyncPipe
fornito da Angular 2.
Importante
Si noti che la maggior parte dei tubi dovrebbe rientrare nella categoria dei tubi senza stato. Questo è importante per le prestazioni, dal momento che Angular può ottimizzare i tubi senza stato per il rilevatore di modifiche. Quindi usate prudentemente i tubi di stato. In generale, l'ottimizzazione dei tubi in Angular 2 ha un importante miglioramento delle prestazioni rispetto ai filtri in 1.x angolare. In Angular 1 il ciclo di digest ha sempre dovuto rieseguire tutti i filtri anche se i dati non sono stati modificati. In Angular 2, una volta calcolato il valore di una pipe, il rilevatore di modifiche sa di non eseguire nuovamente questa pipe a meno che l'input non cambi.
Implementazione di una pipe stateful
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);
}
}
}
È quindi possibile utilizzare la pipa come al solito:
{{ 1000 | countdown:50 }}
{{ 300 | countdown }}
È importante che anche la tua pipe implementa l'interfaccia di OnDestroy
modo che tu possa ripulire una volta distrutta la pipa. Nell'esempio sopra, è necessario cancellare l'intervallo per evitare perdite di memoria.
Dynamic Pipe
Scenario di utilizzo: una vista tabella è composta da diverse colonne con un diverso formato di dati che deve essere trasformato con pipe differenti.
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>
Risultato
| 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 | ---------------------------------------------------------------------
Test di una pipa
Dato un tubo che inverte una corda
import { Pipe, PipeTransform } from '@angular/core';
@Pipe({ name: 'reverse' })
export class ReversePipe implements PipeTransform {
transform(value: string): string {
return value.split('').reverse().join('');
}
}
Può essere testato configurando il file spec come questo
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');
}));
});