파이프
데이터 자체를 변경하기 보다는 화면에 표시하는 형식만 변경하고 싶을때 사용하는 것
app.component.ts 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 import {Component} from '@angular/core' ;@Component ({ selector: 'app-root' , template: ` <h2>{{today}}</h2> <h2>{{today | date}}</h2> <h2>{{today | date : 'y년 MM월 dd일 HH시 mm분 ss초'}}</h2> ` , styles: [] }) export class AppComponent { title = 'custom-attr-directive' ; today = new Date (); }
파이프는 템플릿 내에서 원하는 형식으로 데이터를 변환하여 표시하는 기능으로, 원본 데이터 자체가 변경되는 것은 아니다. 파이프는 다음과 같이 사용한다.
파이프 사용법 1 2 3 {{value | pipeName}} {{value | pipeName : Option : OptionValue}} {{value | pipeName1 | pipeName2}}
이와 같이 파이프 대상 값 뒤에 연산자(|)를 붙인후 원하는 파이프를 지정한다. (:)으로 구분하여 파이프 옵션을 지정하거나, 파이프를 추가할 수도 있다.
빌트인 파이프
Angular는 다양한 빌트인 파이프를 제공한다.
파이프
의미
date
날짜 형식 변환
json
json 형식 변환
uppercase
대문자 변환
lowercase
소문자 변환
currency
통화 형식 변환
percent
퍼센트 형식 변환
decimal
자리수 형식 변환
slice
문자열 추출
async
비동기 객체 출력
빌트인 파이프 예제 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 import {Component} from '@angular/core' ;import {interval} from 'rxjs' ;import {take} from 'rxjs/operators' ;@Component ({ selector: 'app-root' , template: ` <h3>DatePipe</h3> <p>{{ today | date: 'y년 MM월 dd일 HH시 mm분 ss초' }}</p> <h3>CurrencyPipe</h3> <!-- 한국원:통화기호표시:소숫점위 최소 1자리 소숫점아래 1~2 --> <p>{{ price | currency:'KRW':'symbol':'1.1-2' }}</p> <h3>SlicePipe : array</h3> <ul> <li *ngFor="let i of collection | slice:1:3">{{i}}</li> </ul> <h3>SlicePipe : string</h3> <p>{{ str | slice:0:4 }}</p> <h3>JsonPipe</h3> <pre>{{ object | json }}</pre> <h3>DecimalPipe</h3> <p>{{ pi | number:'3.5' }}</p> <h3>PercentPipe</h3> <p>{{ num | percent:'3.3' }}</p> <h3>UpperCasePipe</h3> <p>{{ str | uppercase }}</p> <h3>LowerCasePipe</h3> <p>{{ str | lowercase }}</p> <h3>AsyncPipe</h3> <p>{{ second | async }}</p> ` }) export class AppComponent { today = new Date (); price = 0.1234 ; collection = ['a' , 'b' , 'c' , 'd' ]; str = 'abcdefghij' ; object = {foo: 'bar' , baz: 'qux' , nested: {xyz: 3 }}; pi = 3.141592 ; num = 1.3495 ; second = interval(1000 ).pipe(take(10 )); }
체이닝 파이프
여러 개의 파이프를 조합하여 결과를 출력하는 것을 말한다.
1 2 3 4 5 6 7 8 9 10 11 12 import { Component } from '@angular/core' ;@Component ({ selector: 'app-root' , template: ` <h3>SlicePipe + UpperCasePipe</h3> <p>{{ name | slice:4 | uppercase }}</p> ` }) export class AppComponent { name = 'Lee ung-mo' ; }
위 코드의 slice:4 파이프는 4번째 문자부터 마지막 문자까지를 잘라내고, 그걸 전부 대문자로 출력하는 예제이다. 출력하면 ‘UNG-MO’가 출력된다.
커스텀 파이프
사용자가 직접 파이프를 만들어서 사용할 수도 있다.
먼저 아무프로젝트나 생성하고 프로젝트 안에 파이프를 추가한다.
1 2 3 ng new pipe-custom -t -s -S cd pipe-customng g pipe reverse // reverse라는 파이프 파일을 생성함
프로젝트와 pipe 파일이 생성되면 pipe 파일을 수정한다.
reverse.pipe.ts 1 2 3 4 5 6 7 8 9 10 11 12 import {Pipe, PipeTransform} from '@angular/core' ;@Pipe ({ name: 'reverse' }) export class ReversePipe implements PipeTransform { transform(value = '' ): string { return value.split('' ).reverse().join('' ); } }
파이프는 @Pipe 데코레이터로 장식된 클래스이고, @Pipe 메타데이터 객체의 name 프로퍼티에 파이프의 식별자를 지정한다. 파이프 클래스는 PipeTransform 인터페이스의 추상 메소드 transform를 구현해야 한다. transform 메소드는 파이프의 대상인 값(value)와 옵션(args)를 인자로 받고 변환된 값을 반환한다.
angular cli로 pipe를 생성하면 app.module.ts에 자동으로 등록된다.
app.module.ts 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 import { BrowserModule } from '@angular/platform-browser' ;import { NgModule } from '@angular/core' ;import { AppRoutingModule } from './app-routing.module' ;import { AppComponent } from './app.component' ;import { ReversePipe } from './reverse.pipe' ;@NgModule ({ declarations: [ AppComponent, ReversePipe ], imports: [ BrowserModule, ], providers: [], bootstrap: [AppComponent] }) export class AppModule { }
커스텀 파이프는 빌트인 파이프와 동일한 방법으로 사용한다.
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 import {Component} from '@angular/core' ;@Component ({ selector: 'app-root' , template: ` <input type="text" [(ngModel)]="value"/> {{value |reverse}} ` , styles: [] }) export class AppComponent { value: string ; constructor ( ) { } }
파이프와 변화감지
변화감지는 상태의 변화를 감지하여 뷰에 반영하는 것으로 데이터 바인딩이 이에 해당한다.
간단한 todo 예제를 통해 파이프의 변화감지를 알 수 있다.
프로젝트를 생성한다 (위의 내용반복)
todo 컴포넌트를 생성한다.
limit 파이프를 생성하고 수정한다. (최대 5개까지만 리스트가 보이는 파이프)
limit.pipe.ts 1 2 3 4 5 6 7 8 9 10 11 12 13 14 import {Pipe, PipeTransform} from '@angular/core' ;import {Todo} from './todos.component' ;@Pipe ({ name: 'limit' , pure: false }) export class LimitPipe implements PipeTransform { transform(todos: Todo[], limit: number ): Todo[] { return todos.filter((el, i ) => i < limit); } }
todo 컴포넌트를 수정한다. (limit 파이프 반영)
todo.component.ts 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 import {Component, OnInit} from '@angular/core' ;export interface Todo { id: number ; content: string ; completed: boolean ; } @Component ({ selector: 'app-todos' , template: ` <input type="text" #todo> <button (click)="add(todo.value)">add</button> <ul> <!-- 1) 컴포넌트에 limit 파이프를 적용한다. --> <li *ngFor="let todo of (todos | limit : 5)" (click)="complete(todo.id)" [class.completed]="todo.completed">{{todo.content}}</li> </ul> <pre>{{todos | json}}</pre> ` , styles: [` .completed { text-decoration: line-through; }` ]}) export class TodosComponent { todos: Todo[] = [ {id: 1 , content: 'HTML' , completed: false }, {id: 2 , content: 'css' , completed: false }, {id: 3 , content: 'gs' , completed: false }, ]; constructor ( ) { } add(content: string ) { this .todos = [...this.todos, {id: this .getNextId(), content, completed: false }]; } complete(id: number ) { this .todos = this .todos.map(todo => todo.id === id ? ({...todo, completed: !todo.completed}) : todo); } private getNextId() { return !this .todos.length ? 1 : Math .max(...this.todos.map(({id} ) => id)) + 1 ; } }
2) 이처럼 파이프를 사용하려면 코드 수정이 불가피한데 이를 피하기 위해서 angular에서는 비순수 파이프를 제공한다.
순수 파이프와 비순수 파이프
파이프는 순수 파이프와 비순수 파이프로 분류할 수 있다. 비순수 파이프는 메타데이터 객체의 pure 프로퍼티에 false를 지정한 것이다. pure 프로퍼티를 생략하면 순수 파이프로 동작한다.
비순수 파이프 1 2 3 4 5 ... @Pipe ({ name :'limit' , pure : false })
위 limit 파이프를 비순수 파이프로 변경하면 push를 사용하여도 변화감지가 작동한다. 하지만 비순수 파이프를 사용하면 빈번하게 파이프가 호출되어 퍼포먼스 측면에서 좋지 않으므로 주의한다.
순수 파이프는 기본 자료형의 값 또는 객체 참조의 변경과 같은 순수한 변경만을 감지하고 파이프를 실행한다. angular는 퍼포먼스를 위해 객체 내부의 변경은 무시하며 순수 파이프를 실행하지 않는다.