@Component({ selector: 'file-detail', template: ` <span>Last Modified:</span> <p>{{file?.lastModified | date}}</p> ` }) class FileDetailComponent { }We still have the familiar sytax of pipe in our templates
@Component({ selector: 'file-detail', template: ` <span>Last Modified:</span> <p>{{file?.lastModified | date:"MM/dd/yy"}}</p> ` }) class FileDetailComponent { }A pipe may accept any number of optional parameters to fine-tune its output.
@Component({ selector: 'file-detail', template: ` <span>Last Modified:</span> <p>{{file?.lastModified | date:"MM/dd/yy"}}</p> <input [(ngModel)]="format"> ` }) class FileDetailComponent { }The parameter value can be any valid template expression such as a string literal or component property. In other words, we can control the format through a binding
@Component({ ... template: ` <span>Last Modified:</span> <p>{{ expression | replace:pattern:replacement}}</p> ` }) class FileDetailComponent { }Can we write our own parameters with regex? Replace pipe Creates a new String with some or all of the matches of a pattern replaced by * a replacement.
@Component({ template: ` <span>Made with:</span> <p>Hello {{name | replace:pattern:'2.0'}}</p>`}) class ReplacePipeComponent { constructor() { this.name = 'Angular 1.5' this.pattern = new RegExp(/(?:\d*\.)?\d+/g); } }https://plnkr.co/edit/vYDCnojcr3PizzQbZNjN?p=preview
@Component({ selector: 'file-detail', template: ` <span>File:</span> <p>{{file | json}}</p> ` }) class FileDetailComponent { }Cool new addition to angular 2 is json pipe, it is very helps with debugging. Still angular pipes are very limited in number, we will end up writing our custom pipes. Let's get to it.
import {Pipe,PipeTransform} from 'angular2/core' @Pipe({name: 'trim'}) export class TrimPipe implements PipeTransform { transform(str:string, [length]) : string { if (!str || !length || str.length <= length) { return (str || ''); } let dots = length <= 3 ? '' : '...'; return str.substr(0, length) + dots; } }A pipe is a class decorated with pipe metadata. We implement the transform method of PipeTransform interface. The @Pipe decorator takes an object with a name property whose value is the pipe name that we'll use within a template expression. Then we can define the transform method to format our input to our desired output.
import {Pipe,PipeTransform} from 'angular2/core' @Pipe({name: 'trim'}) export class TrimPipe implements PipeTransform { transform(str:string, [length]) : string { if (!str || !length || str.length <= length) { return (str || ''); } let dots = length <= 3 ? '' : '...'; return str.substr(0, length) + dots; } }A pipe is a class decorated with pipe metadata. We implement the transform method of PipeTransform interface. The @Pipe decorator takes an object with a name property whose value is the pipe name that we'll use within a template expression. Then we can define the transform method to format our input to our desired output.
import {Pipe,PipeTransform} from 'angular2/core' @Pipe({name: 'trim'}) export class TrimPipe implements PipeTransform { transform(str:string, [length]) : string { if (!str || !length || str.length <= length) { return (str || ''); } let dots = length <= 3 ? '' : '...'; return str.substr(0, length) + dots; } }A pipe is a class decorated with pipe metadata. We implement the transform method of PipeTransform interface. The @Pipe decorator takes an object with a name property whose value is the pipe name that we'll use within a template expression. Then we can define the transform method to format our input to our desired output.
import {Pipe, PipeTransform} from 'angular2/core'; @Pipe({name: 'shared'}) export class SharedPipe implements PipeTransform { transform(files:File[]) { return files.filter(file => file.shared); } }What makes angular2 pipes more efficient is the way it detects change. By default angular2 pipes are pure. What is a pure pipe?
Angular executes a pure pipe only when it detects a pure change to the input value.
class FilesComponent { constructor(){...} this.files.push(newFile); }A pure change is either a change to a primitive input value (String, Number, Boolean, Symbol) or a changed object reference (Date, Array, Function, Object).
@Pipe({name: 'shared', pure: false}) export class SharedPipe implements PipeTransform { transform(files:File[]) { return files.filter(file => file.shared); } }Angular executes an impure pipe during every component change detection cycle. An impure pipe will be called a lot, as often as every keystroke or mouse-move.
import {Observable} from 'rxjs/Observable'; @Component(...) class FilesListComponent { contacts: Observable<Array<File>>; constructor(filesService: FilesService) { this.files = filesService.getFiles(); } }Angular AsyncPipe is an interesting example of an impure pipe. The Async pipe can receive a Promise or Observable as input and subscribe to the input changes automatically. It is also stateful. The pipe maintains a subscription to the input Observable and keeps delivering values from that Observable as they arrive.
import {Observable} from 'rxjs/Observable'; @Component(...) class FilesListComponent { contacts: Observable<Array<Contact>>; constructor(filesService: FilesService) { this.files = filesService.getFiles(); } }The Async pipe saves boilerplate in the component code. The component doesn't have to subscribe to the async data source, it doesn't extract the resolved values and expose them for binding, and the component doesn't have to unsubscribe when it is destroyed (a potent source of memory leaks).
@Component({ template: <ul> <li *ngFor="let file of files | async"> ... </li> </ul> ` }) class FilesListComponent {...}
@Component({ template: ` <ul> <li *ngFor="let file of files | async"> ... </li> </ul> ` }) class FilesListComponent {...}
@Pipe({name: 'fetch'}) export class FetchJsonPipe implements PipeTransform{ private fetched:any = null; constructor(private _http: Http) { } transform(url:string):any { this.fetched = null; this._http.get(url) .map( result => result.json() ) .subscribe( result => this.fetched = result ) } return this.fetched; } }You are in trouble if you make this inpure
<div *ngfor="let file of ('filesApiUrl' | fetch) | async"> {{file.name}} </div>This looks great but still not an ideal way
<div *ngfor="let file of userFileStore | async"> {{file.name}} </div>