(docs) devguide pipes: add example code and display it

This commit is contained in:
Ward Bell 2015-11-02 00:28:38 -08:00
parent 9b1f2f8239
commit 33a3dba37e
19 changed files with 331 additions and 170 deletions

View File

@ -0,0 +1 @@
src/**/*.js

View File

@ -0,0 +1,21 @@
{
"name": "angular2-pipes",
"version": "1.0.0",
"description": "",
"main": "index.js",
"scripts": {
"tsc": "tsc -p src -w",
"start": "live-server --open=src"
},
"keywords": [],
"author": "",
"license": "ISC",
"dependencies": {
"angular2": "2.0.0-alpha.44",
"systemjs": "0.19.2"
},
"devDependencies": {
"live-server": "^0.8.1",
"typescript": "^1.6.2"
}
}

View File

@ -0,0 +1,46 @@
<!-- async examples at the top so can see them in action -->
<my-hero></my-hero>
<hr>
<hero-list></hero-list>
<hr>
<!-- #docregion hero-birthday-template -->
<p>The hero's birthday is {{ birthday | date }}</p>
<!-- #enddocregion hero-birthday-template-->
<!-- #docregion format-birthday -->
<p>The hero's birthday is {{ birthday | date:"MM/dd/yy" }} /p>
<!-- #enddocregion format-birthday-->
<hr>
<h4>Hero Birthday 2</h4>
<hero-birthday>loading...</hero-birthday>
<hr>
<!-- #docregion chained-birthday -->
<p>
The chained hero's birthday is
{{ birthday | date | uppercase}}
</p>
<!-- #enddocregion chained-birthday -->
<!-- #docregion chained-parameter-birthday -->
<p>
The chained hero's birthday is
{{ ( birthday | date:'fullDate' ) | uppercase}}
</p>
<!-- #enddocregion chained-parameter-birthday -->
<hr>
<power-booster>loading...</power-booster>
<hr>
<power-boost-calculator>loading ..</power-boost-calculator>

View File

@ -0,0 +1,52 @@
import {HeroBirthday as HeroBirthday2} from './hero-birthday.2';
import {PowerBooster} from './power-booster';
import {PowerBoostCalculator} from './power-boost-calculator';
import {HeroListComponent} from './hero-list-component';
// #docregion hero-birthday
import {bootstrap, Component} from 'angular2/angular2'
@Component({
selector: 'hero-birthday',
// #docregion hero-birthday-template
template: `<p>The hero's birthday is {{ birthday | date }}</p>`
// #enddocregion hero-birthday-template
})
export class HeroBirthday {
birthday = new Date(1988,3,15); // April 15, 1988
}
bootstrap(HeroBirthday);
// #enddocregion hero-birthday
// #docregion async-message
@Component({
selector: 'my-hero',
template: 'Message: {{delayedMessage | async}}',
})
class MyHeroAsyncMessageComponent {
delayedMessage:Promise<string> = new Promise((resolve, reject) => {
setTimeout(() => resolve('You are my Hero!'), 500);
});
}
// Initial view: "Message: "
// After 500ms: Message: You are my Hero!"
// #enddocregion async-message
//// Drives the rest of the pipes chapter examples ///
@Component({
selector: 'my-app',
templateUrl: 'app/app.html',
directives:[
HeroBirthday2,
PowerBooster, PowerBoostCalculator,
MyHeroAsyncMessageComponent,
HeroListComponent]
})
class AppComponent {
birthday = new Date(1988,3,15); // April 15, 1988
}
bootstrap(AppComponent);

View File

@ -0,0 +1,21 @@
// #docregion
import {Pipe} from 'angular2/angular2';
/*
* Raise the value exponentially
* Takes an exponent argument that defaults to 1.
* Usage:
* value | exponentialStrength:exponent
* Example:
* {{ 2 | exponentialStrength:10}}
* formats to: 1024
*/
@Pipe({
name: 'exponentialStrength'
})
export class ExponentialStrengthPipe {
transform(value:number, args:string[]) : any {
return Math.pow(value, parseInt(args[0] || '1', 10));
}
}
// #enddocregion

View File

@ -0,0 +1,26 @@
///<reference path="./window.extension.d.ts"/>
// #docregion
import {Pipe} from 'angular2/angular2';
// #docregion pipe-metadata
@Pipe({
name: 'fetch',
pure: false
})
// #enddocregion pipe-metadata
export class FetchJsonPipe {
private fetchedValue:any;
private fetchPromise:Promise<any>;
transform(value:string, args:string[]):any {
if (!this.fetchPromise) {
this.fetchPromise = window.fetch(value)
.then(result => result.json())
.then(json => {
this.fetchedValue = json;
});
}
return this.fetchedValue;
}
}

View File

@ -0,0 +1,16 @@
import {bootstrap, Component} from 'angular2/angular2'
// #docregion hero-birthday2
@Component({
selector: 'hero-birthday',
template: `
<p>The hero's birthday is {{ birthday | date:format }}</p>
<button (click)="toggleFormat()">Toggle Format</button>
`
})
export class HeroBirthday {
birthday = new Date(1988,3,15); // April 15, 1988
get format() { return this.toggle ? 'shortDate' : 'fullDate'}
toggle = true;
toggleFormat() { this.toggle = !this.toggle; }
}
// #enddocregion hero-birthday2

View File

@ -0,0 +1,25 @@
// #docregion
import {bootstrap, Component,
CORE_DIRECTIVES, FORM_DIRECTIVES} from 'angular2/angular2'
import {FetchJsonPipe} from './fetch-json-pipe'
@Component({
selector: 'hero-list',
template: `
<h4>Heroes from JSON File</h4>
<div *ng-for="#hero of ('heroes.json' | fetch) ">
{{hero.name}}
</div>
<p>Heroes as JSON:
{{'heroes.json' | fetch | json}}
</p>
`,
directives:[CORE_DIRECTIVES],
pipes: [FetchJsonPipe]
})
export class HeroListComponent {
/* I've got nothing to do ;-) */
}

View File

@ -0,0 +1,21 @@
// #docregion
import {Component, FORM_DIRECTIVES} from 'angular2/angular2'
import {ExponentialStrengthPipe} from './exponential-strength-pipe'
@Component({
selector: 'power-boost-calculator',
template: `
<h2>Power Boost Calculator</h2>
<div>Normal power: <input [(ng-model)]="power"></div>
<div>Boost factor: <input [(ng-model)]="factor"></div>
<p>
Super Hero Power: {{power | exponentialStrength: factor}}
</p>
`,
pipes: [ExponentialStrengthPipe],
directives: [FORM_DIRECTIVES]
})
export class PowerBoostCalculator {
power = 5;
factor = 1;
}

View File

@ -0,0 +1,15 @@
// #docregion
import {Component} from 'angular2/angular2'
import {ExponentialStrengthPipe} from './exponential-strength-pipe'
@Component({
selector: 'power-booster',
template: `
<h2>Power Booster</h2>
<p>
Super power boost: {{2 | exponentialStrength: 10}}
</p>
`,
pipes: [ExponentialStrengthPipe]
})
export class PowerBooster { }

View File

@ -0,0 +1,3 @@
interface Window {
fetch:(url: string, options?: {}) => Promise<any>
}

View File

@ -0,0 +1,6 @@
[
{"name": "Windstorm"},
{"name": "Bombasto"},
{"name": "Magneto"},
{"name": "Tornado"}
]

View File

@ -0,0 +1,23 @@
<!DOCTYPE html>
<html>
<head>
<title>Pipes</title>
<script src="../node_modules/systemjs/dist/system.src.js"></script>
<script src="../node_modules/angular2/bundles/angular2.dev.js"></script>
<script>
System.config({
packages: {'app': {defaultExtension: 'js'}}
});
System.import('app/app');
</script>
</head>
<body>
<h4>Hero Birthday 1</h4>
<hero-birthday>loading...</hero-birthday>
<hr>
<my-app>loading ...<my-app>
</body>
</html>

View File

@ -0,0 +1,11 @@
{
"compilerOptions": {
"target": "ES5",
"module": "commonjs",
"sourceMap": true,
"emitDecoratorMetadata": true,
"experimentalDecorators": true,
"removeComments": false,
"noImplicitAny": false
}
}

View File

@ -4,7 +4,7 @@ include ../../../../_includes/_util-fns
Getting data could be as simple as creating a local variable or as complex as streaming data over a Websocket. Getting data could be as simple as creating a local variable or as complex as streaming data over a Websocket.
Once data arrive, we could plaster them directly to screen. Once data arrive, we could push their raw `toString` values directly to screen.
That rarely makes for a good user experience. That rarely makes for a good user experience.
Almost everyone prefers a simple birthday date Almost everyone prefers a simple birthday date
(<span style="font-family:courier">April 15, 1988</span>) to the original raw string format (<span style="font-family:courier">April 15, 1988</span>) to the original raw string format
@ -30,23 +30,13 @@ include ../../../../_includes/_util-fns
All date samples are in my plunker All date samples are in my plunker
http://plnkr.co/edit/RDlOma?p=preview http://plnkr.co/edit/RDlOma?p=preview
--> -->
code-example(format="linenums" escape="html").
import {bootstrap, Component} from 'angular2/angular2'
@Component({ +makeExample('pipes/ts/src/app/app.ts', 'hero-birthday')
selector: 'hero-birthday',
template: `<p>The hero's birthday is {{ birthday | date }}</p>`
})
class HeroBirthday {
birthday = new Date(1988,3,15); // April 15, 1988
}
bootstrap(HeroBirthday);
:markdown :markdown
Focus on the component's template to see how we applied the built-in `DatePipe` Focus on the component's template to see how we applied the built-in `DatePipe`
while binding the `birthday` property. while binding the `birthday` property.
code-example(format="linenums" escape="html"). +makeExample('pipes/ts/src/app/app.html', 'hero-birthday-template')(format=".")
<p>The hero's birthday is {{ birthday | date }} </p>
:markdown :markdown
Angular [template syntax](./template-syntax.html#pipe) includes a pipe operator ( | ) which we're Angular [template syntax](./template-syntax.html#pipe) includes a pipe operator ( | ) which we're
@ -75,8 +65,7 @@ code-example(format="linenums" escape="html").
We'll modify our birthday example to give the date pipe a format parameter. We'll modify our birthday example to give the date pipe a format parameter.
The formatted date should display as **<span style="font-family:courier">04/15/88</span>**. The formatted date should display as **<span style="font-family:courier">04/15/88</span>**.
code-example(format="linenums" escape="html"). +makeExample('pipes/ts/src/app/app.html', 'format-birthday')(format=".")
<p>The hero's birthday is {{ birthday | date:"MM/dd/yy" }} </p>
:markdown :markdown
The parameter value can be any valid The parameter value can be any valid
@ -85,25 +74,7 @@ code-example(format="linenums" escape="html").
Let's revise our example to bind the pipe's format parameter Let's revise our example to bind the pipe's format parameter
to the component's `format` property. to the component's `format` property.
code-example(format="linenums" ). +makeExample('pipes/ts/src/app/hero-birthday.2.ts', 'hero-birthday2')
@Component({
selector: 'hero-birthday',
template: `
&lt;p>The hero's birthday is {{ birthday | date:format }}&lt;/p>
&lt;button (click)="toggleFormat()">Toggle Format&lt;/button>
`
})
class HeroBirthday {
birthday = new Date(1988,3,15); // April 15, 1988
format = 'shortDate';
nextFormat = 'fullDate';
toggleFormat() {
let next = this.format;
this.format = this.nextFormat;
this.nextFormat = next;
}
}
:markdown :markdown
We also added a button to the template and bound its click event to the component's `toggleFormat` method. We also added a button to the template and bound its click event to the component's `toggleFormat` method.
@ -111,8 +82,12 @@ code-example(format="linenums" ).
('shortDate') and a longer form ('fullDate'). ('shortDate') and a longer form ('fullDate').
As we click the button, the displayed date alternates between As we click the button, the displayed date alternates between
"**<span style="font-family:courier">04/15/88</span>**" and "**<span style="font-family:courier">04/15/1988</span>**" and
"**<span style="font-family:courier">Friday, April 15, 1988</span>**". "**<span style="font-family:courier">Friday, April 15, 1988</span>**".
figure.image-display
img(src='/resources/images/devguide/pipes/date-format-toggle-anim.gif' alt="Date Format Toggle")
:markdown
.l-sub-section .l-sub-section
:markdown :markdown
Learn more about the `DatePipes` format options in the [API Docs](../api/core/DatePipe-class.html). Learn more about the `DatePipes` format options in the [API Docs](../api/core/DatePipe-class.html).
@ -123,22 +98,15 @@ code-example(format="linenums" ).
so we can display the birthday in uppercase. The following birthday displays as so we can display the birthday in uppercase. The following birthday displays as
**<span style="font-family:courier">APR 15, 1988</span>** **<span style="font-family:courier">APR 15, 1988</span>**
code-example(format="linenums" escape="html"). +makeExample('pipes/ts/src/app/app.html', 'chained-birthday')
<p>
The chained hero's birthday is
{{ birthday | date | uppercase}}
</p>
:markdown :markdown
If we pass a parameter to a filter, we have to add parentheses If we pass a parameter to a filter, we have to add parentheses
to help the template compiler with the evaluation order. to help the template compiler with the evaluation order.
The following example displays The following example displays
**<span style="font-family:courier">FRIDAY, APRIL 15, 1988</span>** **<span style="font-family:courier">FRIDAY, APRIL 15, 1988</span>**
code-example(format="linenums" escape="html"). +makeExample('pipes/ts/src/app/app.html', 'chained-parameter-birthday')
<p>
The chained hero's birthday is
{{ ( birthday | date:'fullDate' ) | uppercase}}
</p>
.l-sub-section .l-sub-section
p Future improvements in the template compiler may eliminate the need for parentheses. p Future improvements in the template compiler may eliminate the need for parentheses.
@ -147,35 +115,17 @@ code-example(format="linenums" escape="html").
:markdown :markdown
## Custom Pipes ## Custom Pipes
We can easily create our own pipes. We can write our own custom pipes.
Let's create a custom pipe named `ExponentialStrengthPipe` Let's make a custom pipe named `ExponentialStrengthPipe`
that can boost a hero's powers. that can boost a hero's powers.
Create a new file, `exponential-strength-pipe.ts`, and enter the following:
<!-- <!--
The exponential pipe samples are in my plunker The exponential pipe samples are in my plunker
http://plnkr.co/edit/8Nnnwf?p=preview http://plnkr.co/edit/8Nnnwf?p=preview
--> -->
code-example(format="linenums" escape="html"). +makeExample('pipes/ts/src/app/exponential-strength-pipe.ts')
import {bootstrap, Component, Pipe} from 'angular2/angular2'
/*
* Raise the value exponentially
* Takes an exponent argument that defaults to 1.
* Usage:
* value | exponentialStrength:exponent
* Example:
* {{ 2 | exponentialStrength:10}}
* formats to: 1024
*/
@Pipe({
name: 'exponentialStrength'
})
class ExponentialStrengthPipe {
transform(value:number, args:string[]) : any {
return Math.pow(value, parseInt(args[0] || 1, 10));
}
}
:markdown :markdown
This pipe definition reveals several few key points This pipe definition reveals several few key points
@ -191,21 +141,10 @@ code-example(format="linenums" escape="html").
* There will be one item in the array for each parameter passed to the pipe * There will be one item in the array for each parameter passed to the pipe
* `transform` returns a modified value that Angular converts to a string. * `transform` returns a modified value that Angular converts to a string.
Now let's create a component to demonstrate our pipe and bootstrap it. Now let's create a component to demonstrate our pipe.
+makeExample('pipes/ts/src/app/power-booster.ts')
code-example(format="linenums" escape="html"). figure.image-display
@Component({ img(src='/resources/images/devguide/pipes/power-booster.png' alt="Power Booster")
selector: 'power-booster',
template: `
<p>
Super power boost: {{2 | exponentialStrength: 10}}
</p>
`,
pipes: [ExponentialStrengthPipe]
})
class PowerBooster { }
bootstrap(PowerBooster);
:markdown :markdown
Two things to note: Two things to note:
@ -230,28 +169,11 @@ code-example(format="linenums" escape="html").
We could upgrade the example to a "Power Boost Calculator" that combines We could upgrade the example to a "Power Boost Calculator" that combines
our pipe and two-way data binding with `ng-model`. our pipe and two-way data binding with `ng-model`.
code-example(format="linenums" ). +makeExample('pipes/ts/src/app/power-boost-calculator.ts')
import {bootstrap, Component, FORM_DIRECTIVES, Pipe} from 'angular2/angular2'
@Component({ figure.image-display
selector: 'power-boost-calculator', img(src='/resources/images/devguide/pipes/power-boost-calculator.png' alt="Power Boost Calculator")
template: ` :markdown
&lt;h2>Power Boost Calculator&lt;/h2>
&lt;div>Normal power: &lt;input [(ng-model)]="power">&lt;/div>
&lt;div>Boost factor: &lt;input [(ng-model)]="factor">&lt;/div>
&lt;p>
Super Hero Power: {{power | exponentialStrength: factor}}
&lt;/p>
`,
pipes: [ExponentialStrengthPipe],
directives: [FORM_DIRECTIVES]
})
class PowerBoosterCalculator {
power = 5;
factor = 1;
}
bootstrap(PowerBoosterCalculator);
.l-main-section .l-main-section
:markdown :markdown
@ -276,20 +198,7 @@ code-example(format="linenums" ).
It is stateful because the pipe maintains a subscription to the input and its returned values depend on that subscription. It is stateful because the pipe maintains a subscription to the input and its returned values depend on that subscription.
In the next example, we bind a simple promise to a view with the async pipe. In the next example, we bind a simple promise to a view with the async pipe.
+makeExample('pipes/ts/src/app/app.ts', 'async-message')
code-example(format="linenums").
@Component({
selector: 'my-hero',
template: Message: '{{delayedMessage | async}}',
})
class MyComponent {
delayedMessage:Promise<string> = new Promise((resolve, reject) => {
setTimeout(() => resolve('You are my Hero!'), 500);
});
}
// Initial view: "Message: "
// After 500ms: Message: You are my Hero!"
:markdown :markdown
The Async pipe saves boilerplate in the component code. The Async pipe saves boilerplate in the component code.
@ -302,62 +211,27 @@ code-example(format="linenums").
### Implementing a Stateful Pipe ### Implementing a Stateful Pipe
Pipes are stateless by default. Pipes are stateless by default.
We must declare a pipe to be stateful We must declare a pipe to be stateful
by setting the “pure” property of the @Pipe decorator to `false`. by setting the `pure` property of the `@Pipe` decorator to `false`.
This setting tells Angulars change detection system to This setting tells Angulars change detection system to
check the output of this pipe each cycle, whether its input has changed or not. check the output of this pipe each cycle, whether its input has changed or not.
Here's how we'll decorate our new stateful "FetchJsonPipe" that Here's how we'll decorate our new stateful `FetchJsonPipe` that
makes an HTTP `fetch` request and (eventually) displays the data in the server's response: makes an HTTP `fetch` request and (eventually) displays the data in the server's response:
+makeExample('pipes/ts/src/app/fetch-json-pipe.ts', 'pipe-metadata')
``` :markdown
@Pipe({
name: 'fetch',
pure: false
})
```
Immediately below we have the finished pipe. Its input value is an url to an endpoint that returns a JSON file. Immediately below we have the finished pipe. Its input value is an url to an endpoint that returns a JSON file.
The pipe makes a one-time async request to the server and eventually receives the JSON response. The pipe makes a one-time async request to the server and eventually receives the JSON response.
+makeExample('pipes/ts/src/app/fetch-json-pipe.ts')
:markdown
Next we use this pipe in two template bindings where we
1. display hero names in an `ng-for` repeater
1. chain the fetched results to the built-in `JsonPipe` that renders
the data in JSON format
``` +makeExample('pipes/ts/src/app/hero-list-component.ts')
@Pipe({
name: 'fetch',
pure: false
})
class FetchJsonPipe {
private fetchedValue:any;
private fetchPromise:Promise<any>;
transform(value:string, args:string[]):any {
if (!this.fetchPromise) {
this.fetchPromise = fetch(value)
.then(result => result.json())
.then(json => {
this.fetchedValue = json;
});
}
return this.fetchedValue; figure.image-display
} img(src='/resources/images/devguide/pipes/hero-list.png' alt="Hero List")
}
```
Next we use this pipe in a template binding where we chain the
fetched results to the built-in `JsonPipe` that renders
the data in JSON format:
code-example(format="linenums" escape="html").
@Component({
selector: 'heroes-list'
})
@View({
template: `
Heroes: {{'heroes.json' | fetch | json}}
`,
pipes: [FetchJsonPipe]
})
class HeroesList { /* I've got nothing to do ;-) */ }
bootstrap(HeroesList);
.l-main-section .l-main-section
:markdown :markdown

Binary file not shown.

After

Width:  |  Height:  |  Size: 12 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 33 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 20 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 12 KiB