Angular 2
Rury
Szukaj…
Wprowadzenie
Rura |
Znak jest stosowany do stosowania rur w Angular 2. Rury są bardzo podobne do filtrów w AngularJS, ponieważ oba pomagają w transformacji danych do określonego formatu.
Parametry
Funkcja / parametr | Wyjaśnienie |
---|---|
@Pipe ({name, pure}) | metadane dla potoku, muszą bezpośrednio poprzedzać klasę potoku |
nazwa: ciąg | czego użyjesz w szablonie |
czysty: boolean | domyślnie true, zaznacz to jako false, aby twoja rura była częściej oceniana |
transform (wartość, argumenty []?) | funkcja wywoływana w celu przekształcenia wartości w szablonie |
wartość: dowolna | wartość, którą chcesz przekształcić |
args: any [] | argumenty, które mogą być potrzebne, zawarte w transformacji. Oznacz opcjonalne argumenty za pomocą? operator taki jak transformacja (wartość, arg1, arg2?) |
Uwagi
Ten temat obejmuje Angular2 Pipes , mechanizm do przekształcania i formatowania danych w szablonach HTML w aplikacji Angular2.
Rury łańcuchowe
Rury mogą być powiązane.
<p>Today is {{ today | date:'fullDate' | uppercase}}.</p>
Rury niestandardowe
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 { }
Wbudowane rury
Angular2 ma kilka wbudowanych rur:
Rura | Stosowanie | Przykład |
---|---|---|
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 |
Są inni. Poszukaj tutaj ich dokumentacji.
Przykład
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-booking.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>
Wynik
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.
Debugowanie za pomocą JsonPipe
JsonPipe może służyć do debugowania stanu dowolnego wewnętrznego.
Kod
@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]}};
}
Wynik
Without JSON Pipe:
object
With JSON pipe:
{object:{foo: 'bar', baz: 'qux', nested: {xyz: 3, numbers: [1, 2, 3, 4, 5]}}
Globalnie dostępna rura niestandardowa
Aby niestandardowa rura była dostępna dla całej aplikacji, Podczas ładowania aplikacji, rozszerzając 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 tutaj: https://scotch.io/tutorials/create-a-globally-available-custom-pipe-in-angular-2
Tworzenie niestandardowej rury
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{ }
Rozpakuj wartości asynchroniczne za pomocą potoku asynchronicznego
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']);
}
Staje się:
<h1>Hello, Misko</h1>
Your Friends are:
<ul>
<li>
Igor
</li>
</ul>
Rozszerzanie istniejącej rury
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
}
}
}
Stanowe rury
Angular 2 oferuje dwa różne typy rur - bezpaństwowe i stanowe. Rury są domyślnie bezstanowe. Możemy jednak zaimplementować stanowe potoki, ustawiając pure
właściwość na false
. Jak widać w sekcji parametrów, możesz podać name
i zadeklarować, czy potok powinien być czysty, czy nie, co oznacza stanowe lub bezstanowe. Podczas gdy dane przepływają przez potok bezstanowy (który jest czystą funkcją), który niczego nie zapamiętuje, dane mogą być zarządzane i zapamiętywane przez stanowe potoki. Dobrym przykładem stanowego potoku jest AsyncPipe
zapewniany przez Angular 2.
Ważny
Zauważ, że większość rur powinna należeć do kategorii rur bezstanowych. Jest to ważne ze względu na wydajność, ponieważ Angular może zoptymalizować bezstanowe rury do detektora zmian. Dlatego używaj ostrożnie stanowych rur. Ogólnie rzecz biorąc, optymalizacja rur w Angular 2 ma znaczące ulepszenie wydajności w stosunku do filtrów w Angular 1.x. W Angular 1 cykl podsumowania zawsze musiał ponownie uruchamiać wszystkie filtry, nawet jeśli dane w ogóle się nie zmieniły. W Angularze 2, po obliczeniu wartości potoku, detektor zmian wie, że nie będzie mógł ponownie uruchomić tego potoku, chyba że zmieni się wejście.
Implementacja stanowej potoku
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);
}
}
}
Następnie możesz użyć potoku w zwykły sposób:
{{ 1000 | countdown:50 }}
{{ 300 | countdown }}
Ważne jest, aby twoja rura implementowała również interfejs OnDestroy
, abyś mógł wyczyścić po zniszczeniu. W powyższym przykładzie konieczne jest wyczyszczenie interwału, aby uniknąć wycieków pamięci.
Rura dynamiczna
Scenariusz przypadku użycia: widok tabeli składa się z różnych kolumn o różnych formatach danych, które należy przekształcić za pomocą różnych potoków.
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>
Wynik
| 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 | ---------------------------------------------------------------------
Testowanie rury
Biorąc pod uwagę rurę, która odwraca ciąg
import { Pipe, PipeTransform } from '@angular/core';
@Pipe({ name: 'reverse' })
export class ReversePipe implements PipeTransform {
transform(value: string): string {
return value.split('').reverse().join('');
}
}
Można to przetestować konfigurując plik specyfikacji w ten sposób
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');
}));
});