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');
  }));
});


Modified text is an extract of the original Stack Overflow Documentation
Licencjonowany na podstawie CC BY-SA 3.0
Nie związany z Stack Overflow